home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / sun3.md / vmSun.c < prev    next >
C/C++ Source or Header  |  1991-08-09  |  118KB  |  4,132 lines

  1. /* vmSunMach.c -
  2.  *
  3.  *         This file contains all hardware dependent routines for Sun2's and
  4.  *    Sun3's.  I will not attempt to explain the Sun mapping hardware in 
  5.  *    here.  See the Sun2 and Sun3 architecture manuals for details on
  6.  *    the mapping hardware.
  7.  *
  8.  * Copyright (C) 1985 Regents of the University of California
  9.  * All rights reserved.
  10.  */
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /sprite/src/kernel/vm/sun3.md/RCS/vmSun.c,v 9.20 91/08/09 15:01:26 shirriff Exp $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16. #include <sprite.h>
  17. #include <vmSunConst.h>
  18. #include <machMon.h>
  19. #include <vm.h>
  20. #include <vmInt.h>
  21. #include <vmMach.h>
  22. #include <vmMachInt.h>
  23. #include <vmTrace.h>
  24. #include <list.h>
  25. #include <mach.h>
  26. #include <proc.h>
  27. #include <sched.h>
  28. #include <stdlib.h>
  29. #include <sync.h>
  30. #include <sys.h>
  31. #include <dbg.h>
  32. #include <net.h>
  33. #include <stdio.h>
  34. #include <bstring.h>
  35.  
  36. #ifndef multiprocessor
  37.  
  38. #undef MASTER_LOCK
  39. #define MASTER_LOCK(mutexPtr)
  40. #undef MASTER_UNLOCK
  41. #define MASTER_UNLOCK(mutexPtr)
  42.  
  43. #else
  44.  
  45. /*
  46.  * The master lock to synchronize access to pmegs and context.
  47.  */
  48. static Sync_Semaphore vmMachMutex;
  49. static Sync_Semaphore volatile *vmMachMutexPtr = &vmMachMutex;
  50.  
  51. #endif
  52.  
  53. /*----------------------------------------------------------------------
  54.  * 
  55.  *             Hardware data structures
  56.  *
  57.  * Terminology: 
  58.  *    1) Physical page frame: A frame that contains one hardware page.
  59.  *    2) Virtual page frame:  A frame that contains VMMACH_CLUSTER_SIZE 
  60.  *                hardware pages.
  61.  *    3) Software segment: The segment structure used by the hardware
  62.  *                 independent VM module.
  63.  *    4) Hardware segment: A piece of a hardware context.
  64.  *
  65.  * A hardware context corresponds to a process's address space.  A context
  66.  * is made up of many equal sized hardware segments.  The 
  67.  * kernel is mapped into each hardware context so that the kernel has easy
  68.  * access to user data.  One context (context 0) is reserved for use by
  69.  * kernel processes.  The hardware contexts are defined by the array
  70.  * contextArray which contains an entry for each context.  Each entry 
  71.  * contains a pointer back to the process that is executing in the context 
  72.  * and an array which is an exact duplicate of the hardware segment map for
  73.  * the context.  The contexts are managed by keeping all contexts except for
  74.  * the system context in a list that is kept in LRU order.  Whenever a context 
  75.  * is needed the first context off of the list is used and the context is
  76.  * stolen from the current process that owns it if necessary.
  77.  *
  78.  * PMEGs are allocated to software segments in order to allow pages to be mapped
  79.  * into the segment's virtual address space. There are only a small number of 
  80.  * PMEGs (256) which have to be shared by all segments.  PMEGs that have
  81.  * been allocated to user segments can be stolen at any time.  PMEGs that have
  82.  * been allocated to the system segment cannot be taken away unless the system
  83.  * segment voluntarily gives it up.  In order to manage the PMEGs there are
  84.  * two data structures.  One is an array of PMEG info structures that contains
  85.  * one entry for each PMEG.  The other is an array stored with each software
  86.  * segment struct that contains the PMEGs that have been allocated to the
  87.  * software segment.  Each entry in the array of PMEG info structures
  88.  * contains enough information to remove the PMEG from its software segment.
  89.  * One of the fields in the PMEG info struct is the count of pages that have
  90.  * been validated in the PMEG.  This is used to determine when a PMEG is no
  91.  * longer being actively used.  
  92.  *
  93.  * There are two lists that are used to manage PMEGs.  The pmegFreeList 
  94.  * contains all PMEGs that are either not being used or contain no valid 
  95.  * page map entries; unused ones are inserted at the front of the list 
  96.  * and empty ones at the rear.  The pmegInuseList contains all PMEGs
  97.  * that are being actively used to map user segments and is managed as a FIFO.
  98.  * PMEGs that are being used to map tbe kernel's VAS do not appear on the 
  99.  * pmegInuseList. When a pmeg is needed to map a virtual address, first the
  100.  * free list is checked.  If it is not empty then the first PMEG is pulled 
  101.  * off of the list.  If it is empty then the first PMEG is pulled off of the
  102.  * inUse list.  If the PMEG  that is selected is being used (either actively 
  103.  * or inactively) then it is freed from the software segment that is using it.
  104.  * Once the PMEG is freed up then if it is being allocated for a user segment
  105.  * it is put onto the end of the pmegInuseList.
  106.  *
  107.  * Page frames are allocated to software segments even when there is
  108.  * no PMEG to map it in.  Thus when a PMEG that was mapping a page needs to
  109.  * be removed from the software segment that owns the page, the reference
  110.  * and modify bits stored in the PMEG for the page must be saved.  The
  111.  * array refModMap is used for this.  It contains one entry for each
  112.  * virtual page frame.  Its value for a page frame or'd with the bits stored
  113.  * in the PMEG (if any) comprise the referenced and modified bits for a 
  114.  * virtual page frame.
  115.  * 
  116.  * IMPORTANT SYNCHRONIZATION NOTE:
  117.  *
  118.  * The internal data structures in this file have to be protected by a
  119.  * master lock if this code is to be run on a multi-processor.  Since a
  120.  * process cannot start executing unless VmMach_SetupContext can be
  121.  * executed first, VmMach_SetupContext cannot context switch inside itself;
  122.  * otherwise a deadlock will occur.  However, VmMach_SetupContext mucks with
  123.  * contexts and PMEGS and therefore would have to be synchronized
  124.  * on a multi-processor.  A monitor lock cannot be used because it may force
  125.  * VmMach_SetupContext to be context switched.
  126.  *
  127.  * The routines in this file also muck with other per segment data structures.
  128.  * Access to these data structures is synchronized by our caller (the
  129.  * machine independent module).
  130.  *
  131.  *----------------------------------------------------------------------
  132.  */
  133.  
  134. /*
  135.  * Machine dependent flags for the flags field in the Vm_VirtAddr struct.
  136.  * We are only allowed to use the second byte of the flags.
  137.  *
  138.  *    USING_MAPPED_SEG        The parsed virtual address falls into
  139.  *                    the mapping segment.
  140.  */
  141. #define    USING_MAPPED_SEG    0x100
  142.  
  143. /*
  144.  * Macros to get to and from hardware segments and pages.
  145.  */
  146. #define PageToSeg(page) ((page) >> (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  147. #define SegToPage(seg) ((seg) << (VMMACH_SEG_SHIFT - VMMACH_PAGE_SHIFT))
  148.  
  149. /*
  150.  * Convert from page to hardware segment, with correction for
  151.  * any difference between virtAddrPtr offset and segment offset.
  152.  * (This difference will only happen for shared segments.)
  153. */
  154. #define PageToOffSeg(page,virtAddrPtr) (PageToSeg((page)- \
  155.     segOffset(virtAddrPtr)+(virtAddrPtr->segPtr->offset)))
  156.  
  157. /*
  158.  * Macro to set all page map entries for the given virtual address.
  159.  */
  160. #define    SET_ALL_PAGE_MAP(virtAddr, pte) { \
  161.     int    __i; \
  162.     for (__i = 0; __i < VMMACH_CLUSTER_SIZE; __i++) { \
  163.     VmMachSetPageMap((Address)((virtAddr) + __i * VMMACH_PAGE_SIZE_INT),\
  164.     (VmMachPTE)((pte) + __i)); \
  165.     } \
  166. }
  167.  
  168. /*
  169.  * PMEG table entry structure.
  170.  */
  171. typedef struct {
  172.     List_Links            links;        /* Links so that the pmeg */
  173.                         /* can be in a list */
  174.     struct      Vm_Segment      *segPtr;        /* Back pointer to segment that
  175.                                                    this cluster is in */
  176.     int                hardSegNum;    /* The hardware segment number
  177.                            for this pmeg. */
  178.     int                pageCount;    /* Count of resident pages in
  179.                          * this pmeg. */
  180.     int                lockCount;    /* The number of times that
  181.                          * this PMEG has been locked.*/
  182.     int                flags;        /* Flags defined below. */
  183.  
  184. } PMEG;
  185.  
  186. /*
  187.  * Flags to indicate the state of a pmeg.
  188.  *
  189.  *    PMEG_DONT_ALLOC    This pmeg should not be reallocated.  This is 
  190.  *            when a pmeg cannot be reclaimed until it is
  191.  *            voluntarily freed.
  192.  *    PMEG_NEVER_FREE    Don't ever free this pmeg no matter what anybody says.
  193.  */
  194. #define    PMEG_DONT_ALLOC        0x1
  195. #define    PMEG_NEVER_FREE        0x2
  196.  
  197. /*
  198.  * Pmeg information.  pmegArray contains one entry for each pmeg.  pmegFreeList
  199.  * is a list of all pmegs that aren't being actively used.  pmegInuseList
  200.  * is a list of all pmegs that are being actively used.
  201.  */
  202. static    PMEG           pmegArray[VMMACH_NUM_PMEGS];
  203. static    List_Links       pmegFreeListHeader;
  204. static    List_Links       *pmegFreeList = &pmegFreeListHeader;
  205. static    List_Links       pmegInuseListHeader;
  206. static    List_Links       *pmegInuseList = &pmegInuseListHeader;
  207.  
  208. /*
  209.  * The context table structure.
  210.  */
  211. typedef struct VmMach_Context {
  212.     List_Links             links;      /* Links so that the contexts can be
  213.                          in a list. */
  214.     struct Proc_ControlBlock *procPtr;    /* A pointer to the process table entry
  215.                        for the process that is running in
  216.                        this context. */
  217.                     /* A reflection of the hardware context
  218.                      * map. */
  219.     unsigned char          map[VMMACH_NUM_SEGS_PER_CONTEXT];
  220.     int                 context;    /* Which context this is. */
  221.     int                 flags;    /* Defined below. */
  222. } VmMach_Context;
  223.  
  224. /*
  225.  * Context flags:
  226.  *
  227.  *         CONTEXT_IN_USE    This context is used by a process.
  228.  */
  229. #define    CONTEXT_IN_USE    0x1
  230.  
  231. /*
  232.  * Context information.  contextArray contains one entry for each context. 
  233.  * contextList is a list of contexts in LRU order.
  234.  */
  235. static    VmMach_Context    contextArray[VMMACH_NUM_CONTEXTS];
  236. static    List_Links       contextListHeader;
  237. static    List_Links       *contextList = &contextListHeader;
  238.  
  239. /*
  240.  * Map containing one entry for each virtual page.
  241.  */
  242. static    VmMachPTE        *refModMap;
  243.  
  244. /*
  245.  * Macros to translate from a virtual page to a physical page and back.
  246.  */
  247. #define    VirtToPhysPage(pfNum) ((pfNum) << VMMACH_CLUSTER_SHIFT)
  248. #define    PhysToVirtPage(pfNum) ((pfNum) >> VMMACH_CLUSTER_SHIFT)
  249.  
  250. /*
  251.  * Macro to get a pointer into a software segment's hardware segment table.
  252.  */
  253. #ifdef CLEAN
  254. #define GetHardSegPtr(machPtr, segNum) \
  255.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset)
  256. #else
  257. #define GetHardSegPtr(machPtr, segNum) \
  258.     ( ((unsigned)((segNum) - (machPtr)->offset) > (machPtr)->numSegs) ? \
  259.     (panic("Invalid segNum\n"),(machPtr)->segTablePtr) : \
  260.     ((machPtr)->segTablePtr + (segNum) - (machPtr)->offset) )
  261. #endif
  262.  
  263. /*
  264.  * The maximum amount of kernel code + data available. 
  265.  */
  266. int    vmMachKernMemSize = VMMACH_MAX_KERN_SIZE;
  267.  
  268. /*
  269.  * Unix compatibility debug flag.
  270.  */
  271. extern int    debugVmStubs;
  272.  
  273. /*
  274.  * The segment that is used to map a segment into a process's virtual address
  275.  * space for cross-address-space copies.
  276.  */
  277. #define    MAP_SEG_NUM (VMMACH_MAP_SEG_ADDR >> VMMACH_SEG_SHIFT)
  278.  
  279. static void MMUInit _ARGS_((int firstFreeSegment));
  280. static int GetNumPages _ARGS_((void));
  281. static int PMEGGet _ARGS_((Vm_Segment *softSegPtr, int hardSegNum,
  282.     Boolean flags));
  283. static void PMEGFree _ARGS_((int pmegNum));
  284. ENTRY static Boolean PMEGLock _ARGS_((register VmMach_SegData *machPtr,
  285.     int segNum));
  286. static void ByteFill _ARGS_((register unsigned int fillByte,
  287.     register int numBytes, Address destPtr));
  288. INTERNAL static void SetupContext _ARGS_((register Proc_ControlBlock *procPtr));
  289. INTERNAL void VmMachTracePage _ARGS_((register VmMachPTE pte,
  290.     unsigned int pageNum));
  291. static void PageInvalidate _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  292.     unsigned int virtPage, Boolean segDeletion));
  293. static void VmMach_Unalloc _ARGS_((VmMach_SharedData *sharedData,
  294.     Address addr));
  295.  
  296. static    VmMach_SegData    *sysMachPtr;
  297. Address            vmMachPTESegAddr;
  298. Address            vmMachPMEGSegAddr;
  299.  
  300. static    Boolean        printedSegTrace;
  301. static    PMEG        *tracePMEGPtr;
  302.  
  303.  
  304. /*
  305.  * ----------------------------------------------------------------------------
  306.  *
  307.  * VmMach_BootInit --
  308.  *
  309.  *      Do hardware dependent boot time initialization.
  310.  *
  311.  * Results:
  312.  *      None.
  313.  *
  314.  * Side effects:
  315.  *      Hardware page map for the kernel is initialized.  Also the various size
  316.  *     fields are filled in.
  317.  *
  318.  * ----------------------------------------------------------------------------
  319.  */
  320. void
  321. VmMach_BootInit(pageSizePtr, pageShiftPtr, pageTableIncPtr, kernMemSizePtr,
  322.         numKernPagesPtr, maxSegsPtr, maxProcessesPtr)
  323.     int    *pageSizePtr;
  324.     int    *pageShiftPtr;
  325.     int    *pageTableIncPtr;
  326.     int    *kernMemSizePtr;
  327.     int    *numKernPagesPtr;
  328.     int    *maxSegsPtr;
  329.     int *maxProcessesPtr;
  330. {
  331.     register Address    virtAddr;
  332.     register int    i;
  333.     int            kernPages;
  334.     int            numPages;
  335.  
  336. #ifdef multiprocessor
  337.     Sync_SemInitDynamic(&vmMachMutex, "Vm:vmMachMutex");
  338. #endif
  339.  
  340.     kernPages = VMMACH_BOOT_MAP_PAGES;
  341.     /*
  342.      * Map all of the kernel memory that we might need one for one.  We know
  343.      * that the monitor maps the first part of memory one for one but for some
  344.      * reason it doesn't map enough.  We assume that the pmegs have been
  345.      * mapped correctly.
  346.      */
  347.     for (i = 0, virtAddr = (Address)mach_KernStart; 
  348.      i < kernPages;
  349.      i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  350.         VmMachSetPageMap(virtAddr, 
  351.         (VmMachPTE)(VMMACH_KRW_PROT | VMMACH_RESIDENT_BIT | i));
  352.     }
  353.  
  354.     /*
  355.      * Do boot time allocation.
  356.      */
  357.     sysMachPtr = (VmMach_SegData *)Vm_BootAlloc(sizeof(VmMach_SegData) + 
  358.                         VMMACH_NUM_SEGS_PER_CONTEXT);
  359.     numPages = GetNumPages();
  360.     refModMap = (VmMachPTE *)Vm_BootAlloc(sizeof(VmMachPTE) * numPages);
  361.  
  362.     /*
  363.      * Return lots of sizes to the machine independent module who called us.
  364.      */
  365.     *pageSizePtr = VMMACH_PAGE_SIZE;
  366.     *pageShiftPtr = VMMACH_PAGE_SHIFT;
  367.     *pageTableIncPtr = VMMACH_PAGE_TABLE_INCREMENT;
  368.     /*
  369.      * Set max size for kernel code and data to vmMachKernMemSize or
  370.      * the amount of physical memory whichever is less.
  371.      */
  372.     if (vmMachKernMemSize > (numPages*VMMACH_PAGE_SIZE)) {
  373.     vmMachKernMemSize = numPages*VMMACH_PAGE_SIZE;
  374.     }
  375.     *kernMemSizePtr = vmMachKernMemSize;
  376.     *maxProcessesPtr = VMMACH_MAX_KERN_STACKS;
  377.     *numKernPagesPtr = GetNumPages();
  378.     /* 
  379.      * We don't care how many software segments there are so return -1 as
  380.      * the max.
  381.      */
  382.     *maxSegsPtr = -1;
  383. }
  384.  
  385.  
  386. /*
  387.  * ----------------------------------------------------------------------------
  388.  *
  389.  * GetNumPages --
  390.  *
  391.  *     Determine how many pages of physical memory there are.
  392.  *
  393.  * Results:
  394.  *     The number of physical pages.
  395.  *
  396.  * Side effects:
  397.  *     None.
  398.  *
  399.  * ----------------------------------------------------------------------------
  400.  */
  401. static int
  402. GetNumPages()
  403. {
  404. #ifdef sun3
  405.     return(*romVectorPtr->memoryAvail / VMMACH_PAGE_SIZE);
  406. #else
  407.     return(*romVectorPtr->memorySize / VMMACH_PAGE_SIZE);
  408. #endif
  409. }
  410.  
  411. /*
  412.  * ----------------------------------------------------------------------------
  413.  *
  414.  * VmMach_AllocKernSpace --
  415.  *
  416.  *     Allocate memory for machine dependent stuff in the kernels VAS.
  417.  *    This allocates space used to map PMEG and PTE registers
  418.  *    into kernel virtual space.  Two segments are reserved.
  419.  *
  420.  * Results:
  421.  *     The kernel virtual address after the reserved area.
  422.  *
  423.  * Side effects:
  424.  *     Sets vmMachPTESegAddr and vmMachPMEGSegAddr.
  425.  *
  426.  * ----------------------------------------------------------------------------
  427.  */
  428. Address
  429. VmMach_AllocKernSpace(baseAddr)
  430.     Address    baseAddr;
  431. {
  432.     baseAddr = (Address) (((unsigned int)baseAddr + VMMACH_SEG_SIZE - 1) / 
  433.                     VMMACH_SEG_SIZE * VMMACH_SEG_SIZE);
  434.     vmMachPTESegAddr = baseAddr;
  435.     vmMachPMEGSegAddr = baseAddr + VMMACH_SEG_SIZE;
  436.     return(baseAddr + 2 * VMMACH_SEG_SIZE);
  437. }
  438.  
  439.  
  440. /*
  441.  * ----------------------------------------------------------------------------
  442.  *
  443.  * VmMach_Init --
  444.  *
  445.  *     Initialize all virtual memory data structures.
  446.  *
  447.  * Results:
  448.  *     None.
  449.  *
  450.  * Side effects:
  451.  *     All virtual memory linked lists and arrays are initialized.
  452.  *
  453.  * ----------------------------------------------------------------------------
  454.  */
  455. void
  456. VmMach_Init(firstFreePage)
  457.     int    firstFreePage;    /* Virtual page that is the first free for the 
  458.              * kernel. */
  459. {
  460.     register     unsigned char    *segTablePtr;
  461.     register     VmMachPTE    pte;
  462.     register    int         i;
  463.     int             firstFreeSegment;
  464.     Address            virtAddr;
  465.     Address            lastCodeAddr;
  466.     extern    int        etext;
  467.  
  468.     /*
  469.      * Initialize the kernel's hardware segment table.
  470.      */
  471.     vm_SysSegPtr->machPtr = sysMachPtr;
  472.     sysMachPtr->numSegs = VMMACH_NUM_SEGS_PER_CONTEXT;
  473.     sysMachPtr->offset = PageToSeg(vm_SysSegPtr->offset);
  474.     sysMachPtr->segTablePtr =
  475.         (unsigned char *) ((Address)sysMachPtr + sizeof(VmMach_SegData));
  476.     ByteFill(VMMACH_INV_PMEG, VMMACH_NUM_SEGS_PER_CONTEXT,
  477.           (Address)sysMachPtr->segTablePtr);
  478.  
  479.     /*
  480.      * Determine which hardware segment is the first that is not in use.
  481.      */
  482.     firstFreeSegment = ((firstFreePage - 1) << VMMACH_PAGE_SHIFT) / 
  483.                     VMMACH_SEG_SIZE + 1;
  484.     firstFreeSegment += (unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT;
  485.  
  486.     /* 
  487.      * Initialize the PMEG and context tables and lists.
  488.      */
  489.     MMUInit(firstFreeSegment);
  490.  
  491.     /*
  492.      * Initialize the page map.
  493.      */
  494.     bzero((Address)refModMap, sizeof(VmMachPTE) * GetNumPages());
  495.  
  496.     /*
  497.      * The code segment is read only and all other in use kernel memory
  498.      * is read/write.  Since the loader may put the data in the same page
  499.      * as the last code page, the last code page is also read/write.
  500.      */
  501.     lastCodeAddr = (Address) ((unsigned)&etext - VMMACH_PAGE_SIZE);
  502.     for (i = 0, virtAddr = (Address)mach_KernStart;
  503.      i < firstFreePage;
  504.      virtAddr += VMMACH_PAGE_SIZE, i++) {
  505.     if (virtAddr >= (Address)MACH_CODE_START && 
  506.         virtAddr <= lastCodeAddr) {
  507.         pte = VMMACH_RESIDENT_BIT | VMMACH_KR_PROT | 
  508.               i * VMMACH_CLUSTER_SIZE;
  509.     } else {
  510.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | 
  511.               i * VMMACH_CLUSTER_SIZE;
  512.         }
  513.     SET_ALL_PAGE_MAP(virtAddr, pte);
  514.     }
  515.  
  516.     /*
  517.      * Protect the bottom of the kernel stack.
  518.      */
  519.     SET_ALL_PAGE_MAP((Address)mach_StackBottom, (VmMachPTE)0);
  520.  
  521.     /*
  522.      * Invalid until the end of the last segment
  523.      */
  524.     for (;virtAddr < (Address) (firstFreeSegment << VMMACH_SEG_SHIFT);
  525.      virtAddr += VMMACH_PAGE_SIZE) {
  526.     SET_ALL_PAGE_MAP(virtAddr, (VmMachPTE)0);
  527.     }
  528.  
  529.     /* 
  530.      * Zero out the invalid pmeg.
  531.      */
  532.     VmMachPMEGZero(VMMACH_INV_PMEG);
  533.  
  534.     /*
  535.      * Finally copy the kernels context to each of the other contexts.
  536.      */
  537.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  538.     if (i == VMMACH_KERN_CONTEXT) {
  539.         continue;
  540.     }
  541.     VmMachSetUserContext(i);
  542.     for (virtAddr = (Address)mach_KernStart,
  543.          segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  544.          virtAddr < (Address)(VMMACH_NUM_SEGS_PER_CONTEXT*VMMACH_SEG_SIZE);
  545.          virtAddr += VMMACH_SEG_SIZE, segTablePtr++) {
  546.         VmMachSetSegMap(virtAddr, *segTablePtr);
  547.     }
  548.     }
  549.     VmMachSetUserContext(VMMACH_KERN_CONTEXT);
  550.     if (Mach_GetMachineType() == SYS_SUN_3_50) {
  551.     unsigned int vidPage;
  552.  
  553. #define    VIDEO_START    0x100000
  554. #define    VIDEO_SIZE    0x20000
  555.     vidPage = VIDEO_START / VMMACH_PAGE_SIZE;
  556.     if (firstFreePage > vidPage) {
  557.         panic("VmMach_Init: We overran video memory.\n");
  558.     }
  559.     /*
  560.      * On 3/50's the display is kept in main memory beginning at 1 
  561.      * Mbyte and going for 128 kbytes.  Reserve this memory so VM
  562.      * doesn't try to use it.
  563.      */
  564.     for (;vidPage < (VIDEO_START + VIDEO_SIZE) / VMMACH_PAGE_SIZE;
  565.          vidPage++) {
  566.         Vm_ReservePage(vidPage);
  567.     }
  568.     }
  569. }
  570.  
  571.  
  572. /*
  573.  *----------------------------------------------------------------------
  574.  *
  575.  * MMUInit --
  576.  *
  577.  *    Initialize the context table and lists and the Pmeg table and 
  578.  *    lists.
  579.  *
  580.  * Results:
  581.  *    None.
  582.  *
  583.  * Side effects:
  584.  *    Context table and Pmeg table are initialized.  Also context list
  585.  *    and pmeg list are initialized.
  586.  *
  587.  *----------------------------------------------------------------------
  588.  */
  589. static void
  590. MMUInit(firstFreeSegment)
  591.     int        firstFreeSegment;
  592. {
  593.     register    int        i;
  594.     register    PMEG        *pmegPtr;
  595.     register    unsigned char    *segTablePtr;
  596.     int                pageCluster;
  597. #ifdef sun3
  598.     int                dontUse;
  599. #endif
  600.  
  601.     /*
  602.      * Initialize the context table.
  603.      */
  604.     contextArray[VMMACH_KERN_CONTEXT].flags = CONTEXT_IN_USE;
  605.     List_Init(contextList);
  606.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  607.     if (i != VMMACH_KERN_CONTEXT) {
  608.         contextArray[i].flags = 0;
  609.         List_Insert((List_Links *) &contextArray[i], 
  610.             LIST_ATREAR(contextList));
  611.     }
  612.     contextArray[i].context = i;
  613.     }
  614.  
  615.     /*
  616.      * Initialize the page cluster list.
  617.      */
  618.     List_Init(pmegFreeList);
  619.     List_Init(pmegInuseList);
  620.  
  621.     /*
  622.      * Initialize the pmeg structure.
  623.      */
  624.     bzero((Address)pmegArray, VMMACH_NUM_PMEGS * sizeof(PMEG));
  625.     for (i = 0, pmegPtr = pmegArray; 
  626.      i < VMMACH_NUM_PMEGS; 
  627.      i++, pmegPtr++) {
  628.     pmegPtr->segPtr = (Vm_Segment *) NIL;
  629.     pmegPtr->flags = PMEG_DONT_ALLOC;
  630.     }
  631.  
  632. #ifdef sun3
  633.     i = 0;
  634. #else
  635.     /*
  636.      * Segment 0 is left alone because it is required for the monitor.
  637.      */
  638.     pmegArray[0].segPtr = (Vm_Segment *)NIL;
  639.     pmegArray[0].hardSegNum = 0;
  640.     i = 1;
  641. #endif
  642.  
  643.     /*
  644.      * Invalidate all hardware segments from segment 1 up to the beginning
  645.      * of the kernel.
  646.      */
  647.     for (; i < ((unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT); i++) {
  648.     VmMachSetSegMap((Address)(i << VMMACH_SEG_SHIFT), VMMACH_INV_PMEG);
  649.     }
  650.  
  651.     /*
  652.      * Reserve all pmegs that have kernel code or heap.
  653.      */
  654.     for (segTablePtr = vm_SysSegPtr->machPtr->segTablePtr;
  655.          i < firstFreeSegment;
  656.      i++, segTablePtr++) {
  657.     pageCluster = VmMachGetSegMap((Address) (i << VMMACH_SEG_SHIFT));
  658.     pmegArray[pageCluster].pageCount = VMMACH_NUM_PAGES_PER_SEG;
  659.     pmegArray[pageCluster].segPtr = vm_SysSegPtr;
  660.     pmegArray[pageCluster].hardSegNum = i;
  661.     *segTablePtr = pageCluster;
  662.     }
  663.  
  664.     /*
  665.      * Invalidate all hardware segments that aren't in code or heap and are 
  666.      * before the specially mapped page clusters.
  667.      */
  668.     for (; i < VMMACH_FIRST_SPECIAL_SEG; i++, segTablePtr++) {
  669.     VmMachSetSegMap((Address)(i << VMMACH_SEG_SHIFT), VMMACH_INV_PMEG);
  670.     }
  671.  
  672.     /*
  673.      * Mark the invalid pmeg so that it never gets used.
  674.      */
  675.     pmegArray[VMMACH_INV_PMEG].segPtr = vm_SysSegPtr;
  676.     pmegArray[VMMACH_INV_PMEG].flags = PMEG_NEVER_FREE;
  677.  
  678.     /*
  679.      * Now reserve the rest of the page clusters that have been set up by
  680.      * the monitor.  Don't reserve any PMEGs that don't have any valid 
  681.      * mappings in them.
  682.      */
  683.     for (; i < VMMACH_NUM_SEGS_PER_CONTEXT; i++, segTablePtr++) {
  684.     Address        virtAddr;
  685.     int        j;
  686.     VmMachPTE    pte;
  687.     Boolean        inusePMEG;
  688.  
  689.     virtAddr = (Address) (i << VMMACH_SEG_SHIFT);
  690.     pageCluster = VmMachGetSegMap(virtAddr);
  691.     if (pageCluster != VMMACH_INV_PMEG) {
  692.         inusePMEG = FALSE;
  693.         for (j = 0; 
  694.              j < VMMACH_NUM_PAGES_PER_SEG_INT; 
  695.          j++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  696.         pte = VmMachGetPageMap(virtAddr);
  697.         /* printf("%x: %x\n", virtAddr, pte); */
  698.         if ((pte & VMMACH_RESIDENT_BIT) &&
  699.             (pte & (VMMACH_TYPE_FIELD|VMMACH_PAGE_FRAME_FIELD)) != 0) {
  700.             /*
  701.              * A PMEG contains a valid mapping if the resident
  702.              * bit is set and the page frame and type field
  703.              * are non-zero.  On Sun 2/50's the PROM sets
  704.              * the resident bit but leaves the page frame equal
  705.              * to zero.
  706.              */
  707.             if (!inusePMEG) {
  708.             pmegArray[pageCluster].segPtr = vm_SysSegPtr;
  709.             pmegArray[pageCluster].hardSegNum = i;
  710.             pmegArray[pageCluster].flags = PMEG_NEVER_FREE;
  711.             inusePMEG = TRUE;
  712.             }
  713.         } else {
  714.             VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  715.         }
  716.         }
  717.         virtAddr -= VMMACH_SEG_SIZE;
  718.         if (!inusePMEG ||
  719.             (virtAddr >= (Address)VMMACH_DMA_START_ADDR &&
  720.          virtAddr < (Address)(VMMACH_DMA_START_ADDR+VMMACH_DMA_SIZE))) {
  721. #ifdef PRINT_ZAP
  722.         int z;
  723.         /* 
  724.          * We didn't find any valid mappings in the PMEG or the PMEG
  725.          * is in DMA space so delete it.
  726.          */
  727.         printf("Zapping segment at virtAddr %x\n", virtAddr);
  728.         for (z = 0; z < 100000; z++) {
  729.         }
  730. #endif
  731.  
  732.         VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  733.         pageCluster = VMMACH_INV_PMEG;
  734.         }
  735.     }
  736.     *segTablePtr = pageCluster;
  737.     }
  738.  
  739. #ifdef sun3
  740.     /*
  741.      * We can't use the hardware segment that corresponds to the
  742.      * last segment of physical memory for some reason.  Zero it out
  743.      * and can't reboot w/o powering the machine off.
  744.      */
  745.     dontUse = (*romVectorPtr->memoryAvail - 1) / VMMACH_SEG_SIZE;
  746. #endif
  747.  
  748.     /*
  749.      * Now finally, all page clusters that have a NIL segment pointer are
  750.      * put onto the page cluster fifo.  On a Sun-3 one hardware segment is 
  751.      * off limits for some reason.  Zero it out and can't reboot w/o 
  752.      * powering the machine off.
  753.      */
  754.     for (i = 0, pmegPtr = pmegArray; 
  755.      i < VMMACH_NUM_PMEGS;
  756.      i++, pmegPtr++) {
  757.     if (pmegPtr->segPtr == (Vm_Segment *) NIL 
  758. #ifdef sun3
  759.         && i != dontUse
  760. #endif
  761.     ) {
  762.         List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegFreeList));
  763.         pmegPtr->flags = 0;
  764.         VmMachPMEGZero(i);
  765.     }
  766.     }
  767. }
  768.  
  769.  
  770. /*
  771.  * ----------------------------------------------------------------------------
  772.  *
  773.  * VmMach_SegInit --
  774.  *
  775.  *      Initialize hardware dependent data for a segment.
  776.  *
  777.  * Results:
  778.  *      None.
  779.  *
  780.  * Side effects:
  781.  *      Machine dependent data struct and is allocated and initialized.
  782.  *
  783.  * ----------------------------------------------------------------------------
  784.  */
  785. void
  786. VmMach_SegInit(segPtr)
  787.     Vm_Segment    *segPtr;
  788. {
  789.     register    VmMach_SegData    *segDataPtr;
  790.     int                segTableSize;
  791.  
  792.     if (segPtr->type == VM_CODE) {
  793.     segTableSize =
  794.         (segPtr->ptSize + segPtr->offset + VMMACH_NUM_PAGES_PER_SEG - 1) / 
  795.                             VMMACH_NUM_PAGES_PER_SEG;
  796.     } else {
  797.     segTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  798.     }
  799.     segDataPtr = 
  800.     (VmMach_SegData *)malloc(sizeof(VmMach_SegData) + segTableSize);
  801.     segDataPtr->numSegs = segTableSize;
  802.     segDataPtr->offset = PageToSeg(segPtr->offset);
  803.     segDataPtr->segTablePtr =
  804.         (unsigned char *) ((Address)segDataPtr + sizeof(VmMach_SegData));
  805.     ByteFill(VMMACH_INV_PMEG, segTableSize, (Address)segDataPtr->segTablePtr);
  806.     segPtr->machPtr = segDataPtr;
  807.     /*
  808.      * Set the minimum and maximum virtual addresses for this segment to
  809.      * be as small and as big as possible respectively because things will
  810.      * be prevented from growing automatically as soon as segments run into
  811.      * each other.
  812.      */
  813.     segPtr->minAddr = (Address)0;
  814.     segPtr->maxAddr = (Address)0x7fffffff;
  815. }
  816.  
  817. static void    CopySegData();
  818.  
  819.  
  820. /*
  821.  *----------------------------------------------------------------------
  822.  *
  823.  * VmMach_SegExpand --
  824.  *
  825.  *    Allocate more space for the machine dependent structure.
  826.  *
  827.  * Results:
  828.  *    None.
  829.  *
  830.  * Side effects:
  831.  *    Memory allocated for a new hardware segment table.
  832.  *
  833.  *----------------------------------------------------------------------
  834.  */
  835. /*ARGSUSED*/
  836. void
  837. VmMach_SegExpand(segPtr, firstPage, lastPage)
  838.     register    Vm_Segment    *segPtr;    /* Segment to expand. */
  839.     int                firstPage;    /* First page to add. */
  840.     int                lastPage;    /* Last page to add. */
  841. {
  842.     int                newSegTableSize;
  843.     register    VmMach_SegData    *oldSegDataPtr;
  844.     register    VmMach_SegData    *newSegDataPtr;
  845.  
  846.     newSegTableSize = segPtr->ptSize / VMMACH_NUM_PAGES_PER_SEG;
  847.     oldSegDataPtr = segPtr->machPtr;
  848.     if (newSegTableSize <= oldSegDataPtr->numSegs) {
  849.     return;
  850.     }
  851.     newSegDataPtr = 
  852.     (VmMach_SegData *)malloc(sizeof(VmMach_SegData) + newSegTableSize);
  853.     newSegDataPtr->numSegs = newSegTableSize;
  854.     newSegDataPtr->offset = PageToSeg(segPtr->offset);
  855.     newSegDataPtr->segTablePtr =
  856.         (unsigned char *) ((Address)newSegDataPtr + sizeof(VmMach_SegData));
  857.     CopySegData(segPtr, oldSegDataPtr, newSegDataPtr);
  858.     free((Address)oldSegDataPtr);
  859. }
  860.  
  861.  
  862. /*
  863.  *----------------------------------------------------------------------
  864.  *
  865.  * CopySegData --
  866.  *
  867.  *    Copy over the old hardware segment data into the new expanded
  868.  *    structure.
  869.  *
  870.  * Results:
  871.  *    None.
  872.  *
  873.  * Side effects:
  874.  *    The hardware segment table is copied.
  875.  *
  876.  *----------------------------------------------------------------------
  877.  */
  878. ENTRY static void
  879. CopySegData(segPtr, oldSegDataPtr, newSegDataPtr)
  880.     register    Vm_Segment    *segPtr;    /* The segment to add the
  881.                            virtual pages to. */
  882.     register    VmMach_SegData    *oldSegDataPtr;
  883.     register    VmMach_SegData    *newSegDataPtr;
  884. {
  885.     MASTER_LOCK(vmMachMutexPtr);
  886.  
  887.     if (segPtr->type == VM_HEAP) {
  888.     /*
  889.      * Copy over the hardware segment table into the lower part
  890.      * and set the rest to invalid.
  891.      */
  892.     bcopy((Address)oldSegDataPtr->segTablePtr,
  893.         (Address)newSegDataPtr->segTablePtr, oldSegDataPtr->numSegs);
  894.     ByteFill(VMMACH_INV_PMEG,
  895.       newSegDataPtr->numSegs - oldSegDataPtr->numSegs,
  896.       (Address)(newSegDataPtr->segTablePtr + oldSegDataPtr->numSegs));
  897.     } else {
  898.     /*
  899.      * Copy the current segment table into the high part of the
  900.      * new segment table and set the lower part to invalid.
  901.      */
  902.     bcopy((Address)oldSegDataPtr->segTablePtr,
  903.         (Address)(newSegDataPtr->segTablePtr + 
  904.         newSegDataPtr->numSegs - oldSegDataPtr->numSegs),
  905.         oldSegDataPtr->numSegs);
  906.     ByteFill(VMMACH_INV_PMEG, 
  907.         newSegDataPtr->numSegs - oldSegDataPtr->numSegs,
  908.         (Address)newSegDataPtr->segTablePtr);
  909.     }
  910.     segPtr->machPtr = newSegDataPtr;
  911.  
  912.     MASTER_UNLOCK(vmMachMutexPtr);
  913. }
  914.  
  915. static void    SegDelete();
  916.  
  917. /*
  918.  * ----------------------------------------------------------------------------
  919.  *
  920.  * VmMach_SegDelete --
  921.  *
  922.  *      Free hardware dependent resources for this software segment.
  923.  *
  924.  * Results:
  925.  *      None.
  926.  *
  927.  * Side effects:
  928.  *      Machine dependent struct freed and the pointer in the segment
  929.  *    is set to NIL.
  930.  *
  931.  * ----------------------------------------------------------------------------
  932.  */
  933. void
  934. VmMach_SegDelete(segPtr)
  935.     register    Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  936. {
  937.     if (vm_Tracing) {
  938.     Vm_TraceSegDestroy    segDestroy;
  939.  
  940.     segDestroy.segNum = segPtr->segNum;
  941.     VmStoreTraceRec(VM_TRACE_SEG_DESTROY_REC, sizeof(segDestroy),
  942.             (Address)&segDestroy, TRUE);
  943.     }
  944.  
  945.     SegDelete(segPtr);
  946.     free((Address)segPtr->machPtr);
  947.     segPtr->machPtr = (VmMach_SegData *)NIL;
  948. }
  949.  
  950.  
  951. /*
  952.  * ----------------------------------------------------------------------------
  953.  *
  954.  * SegDelete --
  955.  *
  956.  *      Free up any pmegs used by this segment.
  957.  *
  958.  * Results:
  959.  *      None.
  960.  *
  961.  * Side effects:
  962.  *      All pmegs used by this segment are freed.
  963.  *
  964.  * ----------------------------------------------------------------------------
  965.  */
  966. ENTRY static void
  967. SegDelete(segPtr)
  968.     Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  969. {
  970.     register    int         i;
  971.     register    unsigned char     *pmegPtr;
  972.     register    VmMach_SegData    *machPtr;
  973.  
  974.     MASTER_LOCK(vmMachMutexPtr);
  975.  
  976.     machPtr = segPtr->machPtr;
  977.     for (i = 0, pmegPtr = machPtr->segTablePtr;
  978.          i < machPtr->numSegs;
  979.      i++, pmegPtr++) {
  980.     if (*pmegPtr != VMMACH_INV_PMEG) {
  981.         PMEGFree((int) *pmegPtr);
  982.     }
  983.     }
  984.  
  985.     MASTER_UNLOCK(vmMachMutexPtr);
  986. }
  987.  
  988.  
  989. /*
  990.  *----------------------------------------------------------------------
  991.  *
  992.  * VmMach_ProcInit --
  993.  *
  994.  *    Initalize the machine dependent part of the VM proc info.
  995.  *
  996.  * Results:
  997.  *    None.
  998.  *
  999.  * Side effects:
  1000.  *    Machine dependent proc info is initialized.
  1001.  *
  1002.  *----------------------------------------------------------------------
  1003.  */
  1004. void
  1005. VmMach_ProcInit(vmPtr)
  1006.     register    Vm_ProcInfo    *vmPtr;
  1007. {
  1008.     if (vmPtr->machPtr == (VmMach_ProcData *)NIL) {
  1009.     vmPtr->machPtr = (VmMach_ProcData *)malloc(sizeof(VmMach_ProcData));
  1010.     }
  1011.     vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  1012.     vmPtr->machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1013.     vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  1014. }
  1015.  
  1016.  
  1017. /*
  1018.  * ----------------------------------------------------------------------------
  1019.  *
  1020.  * PMEGGet --
  1021.  *
  1022.  *      Return the next pmeg from the list of available pmegs.  If the 
  1023.  *      lock flag is set then the pmeg is removed from the pmeg list.
  1024.  *      Otherwise it is moved to the back.
  1025.  *
  1026.  * Results:
  1027.  *      The pmeg number that is allocated.
  1028.  *
  1029.  * Side effects:
  1030.  *      A pmeg is either removed from the pmeg list or moved to the back.
  1031.  *
  1032.  * ----------------------------------------------------------------------------
  1033.  */
  1034. INTERNAL static int
  1035. PMEGGet(softSegPtr, hardSegNum, flags)
  1036.     Vm_Segment     *softSegPtr;    /* Which software segment this is. */
  1037.     int        hardSegNum;    /* Which hardware segment in the software 
  1038.                    segment that this is */
  1039.     Boolean    flags;        /* Flags that indicate the state of the pmeg. */
  1040. {
  1041.     register PMEG        *pmegPtr;
  1042.     register Vm_Segment        *segPtr;
  1043.     register VmMachPTE        *ptePtr;
  1044.     register VmMach_Context    *contextPtr;
  1045.     register int        i;
  1046.     register VmMachPTE        hardPTE;
  1047.     VmMachPTE            pteArray[VMMACH_NUM_PAGES_PER_SEG_INT];
  1048.     int                     oldContext;
  1049.     int                pmegNum;
  1050.     Address            virtAddr;
  1051.     Boolean            found = FALSE;
  1052.  
  1053.     if (List_IsEmpty(pmegFreeList)) {
  1054.     LIST_FORALL(pmegInuseList, (List_Links *)pmegPtr) {
  1055.         if (pmegPtr->lockCount == 0) {
  1056.         found = TRUE;
  1057.         break;
  1058.         }
  1059.     }
  1060.     if (!found) {
  1061.         panic("Pmeg lists empty\n");
  1062.         return(VMMACH_INV_PMEG);
  1063.     }
  1064.     } else {
  1065.     pmegPtr = (PMEG *)List_First(pmegFreeList);
  1066.     }
  1067.     pmegNum = pmegPtr - pmegArray;
  1068.  
  1069.     if (pmegPtr->segPtr != (Vm_Segment *) NIL) {
  1070.     /*
  1071.      * Need to steal the pmeg from its current owner.
  1072.      */
  1073.     vmStat.machDepStat.stealPmeg++;
  1074.     segPtr = pmegPtr->segPtr;
  1075.     *GetHardSegPtr(segPtr->machPtr, pmegPtr->hardSegNum) = VMMACH_INV_PMEG;
  1076.     virtAddr = (Address) (pmegPtr->hardSegNum << VMMACH_SEG_SHIFT);
  1077.     /*
  1078.      * Delete the pmeg from all appropriate contexts.
  1079.      */
  1080.     oldContext = VmMachGetContextReg();
  1081.         if (segPtr->type == VM_SYSTEM) {
  1082.         for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1083.         VmMachSetContextReg(i);
  1084.         VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1085.         }
  1086.         } else {
  1087.         for (i = 1, contextPtr = &contextArray[1];
  1088.          i < VMMACH_NUM_CONTEXTS; 
  1089.          i++, contextPtr++) {
  1090.         if (contextPtr->flags & CONTEXT_IN_USE) {
  1091.             if (contextPtr->map[pmegPtr->hardSegNum] == pmegNum) {
  1092.             VmMachSetContextReg(i);
  1093.             contextPtr->map[pmegPtr->hardSegNum] = VMMACH_INV_PMEG;
  1094.             VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1095.             }
  1096.             if (contextPtr->map[MAP_SEG_NUM] == pmegNum) {
  1097.             VmMachSetContextReg(i);
  1098.             contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1099.             VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR,
  1100.                     VMMACH_INV_PMEG);
  1101.             }
  1102.         }
  1103.         }
  1104.         }
  1105.     VmMachSetContextReg(oldContext);
  1106.     /*
  1107.      * Read out all reference and modify bits from the pmeg.
  1108.      */
  1109.     if (pmegPtr->pageCount > 0) {
  1110.         Boolean    printedStealPMEG = FALSE;
  1111.  
  1112.         ptePtr = pteArray;
  1113.         VmMachReadAndZeroPMEG(pmegNum, ptePtr);
  1114.         for (i = 0;
  1115.          i < VMMACH_NUM_PAGES_PER_SEG_INT;
  1116.          i++, ptePtr++) {
  1117.         hardPTE = *ptePtr;
  1118.         if ((hardPTE & VMMACH_RESIDENT_BIT) &&
  1119.             (hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT))) {
  1120.             if (vm_Tracing) {
  1121.             if (!printedStealPMEG) {
  1122.                 short    stealPMEGRec;
  1123.  
  1124.                 printedStealPMEG = TRUE;
  1125.                 printedSegTrace = FALSE;
  1126.                 tracePMEGPtr = pmegPtr;
  1127.                 VmStoreTraceRec(VM_TRACE_STEAL_PMEG_REC,
  1128.                         sizeof(short), 
  1129.                         (Address)&stealPMEGRec,TRUE);
  1130.             }
  1131.             VmMachTracePage(hardPTE,
  1132.                 (unsigned int) (VMMACH_NUM_PAGES_PER_SEG_INT - i));
  1133.             } else {
  1134.             refModMap[PhysToVirtPage(hardPTE & VMMACH_PAGE_FRAME_FIELD)]
  1135.              |= hardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  1136.             }
  1137.         }
  1138.         }
  1139.      }
  1140.     }
  1141.  
  1142.     /* Initialize the pmeg and delete it from the fifo.  If we aren't 
  1143.      * supposed to lock this pmeg, then put it at the rear of the list.
  1144.      */
  1145.     pmegPtr->segPtr = softSegPtr;
  1146.     pmegPtr->hardSegNum = hardSegNum;
  1147.     pmegPtr->pageCount = 0;
  1148.     List_Remove((List_Links *) pmegPtr);
  1149.     if (!(flags & PMEG_DONT_ALLOC)) {
  1150.     List_Insert((List_Links *) pmegPtr, LIST_ATREAR(pmegInuseList));
  1151.     }
  1152.     pmegPtr->flags = flags;
  1153.  
  1154.     return(pmegNum);
  1155. }
  1156.  
  1157.  
  1158. /*
  1159.  * ----------------------------------------------------------------------------
  1160.  *
  1161.  * PMEGFree --
  1162.  *
  1163.  *      Return the given pmeg to the pmeg list.
  1164.  *
  1165.  * Results:
  1166.  *      None.
  1167.  *
  1168.  * Side effects:
  1169.  *      The pmeg is returned to the pmeg list.
  1170.  *
  1171.  * ----------------------------------------------------------------------------
  1172.  */
  1173. INTERNAL static void
  1174. PMEGFree(pmegNum)
  1175.     int     pmegNum;    /* Which pmeg to free */
  1176. {
  1177.     register    PMEG    *pmegPtr;
  1178.  
  1179.     pmegPtr = &pmegArray[pmegNum];
  1180.     /*
  1181.      * If this pmeg can never be freed then don't free it.  This case can
  1182.      * occur when a device is mapped into a user's address space.
  1183.      */
  1184.     if (pmegPtr->flags & PMEG_NEVER_FREE) {
  1185.     return;
  1186.     }
  1187.     if (pmegPtr->pageCount > 0) {
  1188.     VmMachPMEGZero(pmegNum);
  1189.     }
  1190.     pmegPtr->segPtr = (Vm_Segment *) NIL;
  1191.     if (pmegPtr->pageCount == 0 || !(pmegPtr->flags & PMEG_DONT_ALLOC)) {
  1192.     List_Remove((List_Links *) pmegPtr);
  1193.     }
  1194.     pmegPtr->flags = 0;
  1195.     pmegPtr->lockCount = 0;
  1196.     /*
  1197.      * Put this pmeg at the front of the pmeg free list.
  1198.      */
  1199.     List_Insert((List_Links *) pmegPtr, LIST_ATFRONT(pmegFreeList));
  1200. }
  1201.  
  1202.  
  1203. /*
  1204.  * ----------------------------------------------------------------------------
  1205.  *
  1206.  * PMEGLock --
  1207.  *
  1208.  *      Increment the lock count on a pmeg.
  1209.  *
  1210.  * Results:
  1211.  *      TRUE if there was a valid PMEG behind the given hardware segment.
  1212.  *
  1213.  * Side effects:
  1214.  *      The lock count is incremented if there is a valid pmeg at the given
  1215.  *    hardware segment.
  1216.  *
  1217.  * ----------------------------------------------------------------------------
  1218.  */
  1219. ENTRY static Boolean
  1220. PMEGLock(machPtr, segNum)
  1221.     register VmMach_SegData    *machPtr;
  1222.     int                segNum;
  1223. {
  1224.     int pmegNum;
  1225.  
  1226.     MASTER_LOCK(vmMachMutexPtr);
  1227.  
  1228.     pmegNum = *GetHardSegPtr(machPtr, segNum);
  1229.     if (pmegNum != VMMACH_INV_PMEG) {
  1230.     pmegArray[pmegNum].lockCount++;
  1231.     MASTER_UNLOCK(vmMachMutexPtr);
  1232.     return(TRUE);
  1233.     } else {
  1234.     MASTER_UNLOCK(vmMachMutexPtr);
  1235.     return(FALSE);
  1236.     }
  1237. }
  1238.  
  1239.  
  1240. /*
  1241.  * ----------------------------------------------------------------------------
  1242.  *
  1243.  * VmMach_SetupContext --
  1244.  *
  1245.  *      Return the value of the context register for the given process.
  1246.  *    It is assumed that this routine is called on a uni-processor right
  1247.  *    before the process starts executing.
  1248.  *    
  1249.  * Results:
  1250.  *      None.
  1251.  *
  1252.  * Side effects:
  1253.  *      The context list is modified.
  1254.  *
  1255.  * ----------------------------------------------------------------------------
  1256.  */
  1257. ENTRY ClientData
  1258. VmMach_SetupContext(procPtr)
  1259.     register    Proc_ControlBlock    *procPtr;
  1260. {
  1261.     register    VmMach_Context    *contextPtr;
  1262.  
  1263.     MASTER_LOCK(vmMachMutexPtr);
  1264.  
  1265.     while (TRUE) {
  1266.     contextPtr = procPtr->vmPtr->machPtr->contextPtr;
  1267.     if (contextPtr != (VmMach_Context *)NIL) {
  1268.         if (contextPtr != &contextArray[VMMACH_KERN_CONTEXT]) {
  1269.         if (vm_Tracing) {
  1270.             Vm_ProcInfo    *vmPtr;
  1271.  
  1272.             vmPtr = procPtr->vmPtr;
  1273.             vmPtr->segPtrArray[VM_CODE]->traceTime = vmTraceTime;
  1274.             vmPtr->segPtrArray[VM_HEAP]->traceTime = vmTraceTime;
  1275.             vmPtr->segPtrArray[VM_STACK]->traceTime = vmTraceTime;
  1276.         }
  1277.         List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  1278.         }
  1279.         MASTER_UNLOCK(vmMachMutexPtr);
  1280.         return((ClientData)contextPtr->context);
  1281.     }
  1282.         SetupContext(procPtr);
  1283.     }
  1284. }
  1285.  
  1286.  
  1287. /*
  1288.  * ----------------------------------------------------------------------------
  1289.  *
  1290.  * SetupContext --
  1291.  *
  1292.  *      Initialize the context for the given process.  If the process does
  1293.  *    not have a context associated with it then one is allocated.
  1294.  *
  1295.  *    Note that this routine runs unsynchronized even though it is using
  1296.  *    internal structures.  See the note above while this is OK.  I
  1297.  *     eliminated the monitor lock because it is unnecessary anyway and
  1298.  *    it slows down context-switching.
  1299.  *    
  1300.  * Results:
  1301.  *      None.
  1302.  *
  1303.  * Side effects:
  1304.  *      The context field in the process table entry and the context list are
  1305.  *     both modified if a new context is allocated.
  1306.  *
  1307.  * ----------------------------------------------------------------------------
  1308.  */
  1309. INTERNAL static void
  1310. SetupContext(procPtr)
  1311.     register    Proc_ControlBlock    *procPtr;
  1312. {
  1313.     register    VmMach_Context    *contextPtr;
  1314.     register    VmMach_SegData    *segDataPtr;
  1315.     register    Vm_ProcInfo    *vmPtr;
  1316.  
  1317.     vmPtr = procPtr->vmPtr;
  1318.     contextPtr = vmPtr->machPtr->contextPtr;
  1319.  
  1320.     if (procPtr->genFlags & (PROC_KERNEL | PROC_NO_VM)) {
  1321.     /*
  1322.      * This is a kernel process or a process that is exiting.
  1323.      * Set the context to kernel and return.
  1324.      */
  1325.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  1326.     vmPtr->machPtr->contextPtr = &contextArray[VMMACH_KERN_CONTEXT];
  1327.     return;
  1328.     }
  1329.  
  1330.     if (contextPtr == (VmMach_Context *)NIL) {
  1331.     /*
  1332.      * In this case there is no context setup for this process.  Therefore
  1333.      * we have to find a context, initialize the context table entry and 
  1334.      * initialize the context stuff in the proc table.
  1335.      */
  1336.     if (List_IsEmpty((List_Links *) contextList)) {
  1337.         panic("SetupContext: Context list empty\n");
  1338.     }
  1339.     /* 
  1340.      * Take the first context off of the context list.
  1341.      */
  1342.     contextPtr = (VmMach_Context *) List_First(contextList);
  1343.     if (contextPtr->flags & CONTEXT_IN_USE) {
  1344.         contextPtr->procPtr->vmPtr->machPtr->contextPtr =
  1345.                             (VmMach_Context *)NIL;
  1346.         vmStat.machDepStat.stealContext++;
  1347.     }
  1348.     /*
  1349.      * Initialize the context table entry.
  1350.      */
  1351.     contextPtr->flags = CONTEXT_IN_USE;
  1352.     contextPtr->procPtr = procPtr;
  1353.     vmPtr->machPtr->contextPtr = contextPtr;
  1354.     VmMachSetContextReg(contextPtr->context);
  1355.     /*
  1356.      * Set the context map.
  1357.      */
  1358.     ByteFill(VMMACH_INV_PMEG,
  1359.           (int)((unsigned int)mach_KernStart >> VMMACH_SEG_SHIFT),
  1360.           (Address)contextPtr->map);
  1361.     segDataPtr = vmPtr->segPtrArray[VM_CODE]->machPtr;
  1362.     bcopy((Address)segDataPtr->segTablePtr, 
  1363.         (Address) (contextPtr->map + segDataPtr->offset),
  1364.         segDataPtr->numSegs);
  1365.     segDataPtr = vmPtr->segPtrArray[VM_HEAP]->machPtr;
  1366.     bcopy((Address)segDataPtr->segTablePtr, 
  1367.         (Address) (contextPtr->map + segDataPtr->offset),
  1368.         segDataPtr->numSegs);
  1369.     segDataPtr = vmPtr->segPtrArray[VM_STACK]->machPtr;
  1370.     bcopy((Address)segDataPtr->segTablePtr, 
  1371.         (Address) (contextPtr->map + segDataPtr->offset),
  1372.         segDataPtr->numSegs);
  1373.     if (vmPtr->sharedSegs != (List_Links *)NIL) {
  1374.         Vm_SegProcList *segList;
  1375.         LIST_FORALL(vmPtr->sharedSegs,(List_Links *)segList) {
  1376.         segDataPtr = segList->segTabPtr->segPtr->machPtr;
  1377.         bcopy((Address)segDataPtr->segTablePtr, 
  1378.             (Address) (contextPtr->map+PageToSeg(segList->offset)),
  1379.             segDataPtr->numSegs);
  1380.         }
  1381.     }
  1382.     if (vmPtr->machPtr->mapSegPtr != (struct Vm_Segment *)NIL) {
  1383.         contextPtr->map[MAP_SEG_NUM] = vmPtr->machPtr->mapHardSeg;
  1384.     } else {
  1385.         contextPtr->map[MAP_SEG_NUM] = VMMACH_INV_PMEG;
  1386.     }
  1387.     /*
  1388.      * Push map out to hardware.
  1389.      */
  1390.     VmMachSegMapCopy((Address)contextPtr->map, 0, (int)mach_KernStart);
  1391.     } else {
  1392.     VmMachSetContextReg(contextPtr->context);
  1393.     }
  1394.     List_Move((List_Links *)contextPtr, LIST_ATREAR(contextList));
  1395. }
  1396.  
  1397.  
  1398. /*
  1399.  * ----------------------------------------------------------------------------
  1400.  *
  1401.  * Vm_FreeContext --
  1402.  *
  1403.  *      Free the given context.
  1404.  *
  1405.  * Results:
  1406.  *      None.
  1407.  *
  1408.  * Side effects:
  1409.  *      The context table and context lists are modified.
  1410.  *
  1411.  * ----------------------------------------------------------------------------
  1412.  */
  1413. ENTRY void
  1414. VmMach_FreeContext(procPtr)
  1415.     register    Proc_ControlBlock    *procPtr;
  1416. {
  1417.     register    VmMach_Context    *contextPtr;
  1418.     register    VmMach_ProcData    *machPtr;
  1419.  
  1420.     MASTER_LOCK(vmMachMutexPtr);
  1421.  
  1422.     machPtr = procPtr->vmPtr->machPtr;
  1423.     contextPtr = machPtr->contextPtr;
  1424.     if (contextPtr == (VmMach_Context *)NIL ||
  1425.         contextPtr->context == VMMACH_KERN_CONTEXT) {
  1426.     MASTER_UNLOCK(vmMachMutexPtr);
  1427.     return;
  1428.     }
  1429.     List_Move((List_Links *)contextPtr, LIST_ATFRONT(contextList));
  1430.     contextPtr->flags = 0;
  1431.     machPtr->contextPtr = (VmMach_Context *)NIL;
  1432.  
  1433.     MASTER_UNLOCK(vmMachMutexPtr);
  1434. }
  1435.  
  1436.  
  1437. /*
  1438.  * ----------------------------------------------------------------------------
  1439.  *
  1440.  * VmMach_ReinitContext --
  1441.  *
  1442.  *      Free the current context and set up another one.  This is called
  1443.  *    by routines such as Proc_Exec that add things to the context and
  1444.  *    then have to abort or start a process running with a new image.
  1445.  *
  1446.  * Results:
  1447.  *      None.
  1448.  *
  1449.  * Side effects:
  1450.  *      The context table and context lists are modified.
  1451.  *
  1452.  * ----------------------------------------------------------------------------
  1453.  */
  1454. void
  1455. VmMach_ReinitContext(procPtr)
  1456.     register    Proc_ControlBlock    *procPtr;
  1457. {
  1458.     VmMach_FreeContext(procPtr);
  1459.     MASTER_LOCK(vmMachMutexPtr);
  1460.     procPtr->vmPtr->machPtr->contextPtr = (VmMach_Context *)NIL;
  1461.     SetupContext(procPtr);
  1462.     MASTER_UNLOCK(vmMachMutexPtr);
  1463. }
  1464.  
  1465. #ifdef sun2
  1466.  
  1467. static int     allocatedPMEG;
  1468. static VmMachPTE intelSavedPTE;        /* The page table entry that is stored
  1469.                      * at the address that the intel page
  1470.                      * has to overwrite. */
  1471. static unsigned int intelPage;        /* The page frame that was allocated.*/
  1472. #endif
  1473.  
  1474.  
  1475. /*
  1476.  * ----------------------------------------------------------------------------
  1477.  *
  1478.  * VmMach_MapIntelPage --
  1479.  *
  1480.  *      Allocate and validate a page for the Intel Ethernet chip.  This routine
  1481.  *    is required in order to initialize the chip.  The chip expects 
  1482.  *    certain stuff to be at a specific virtual address when it is 
  1483.  *    initialized.  This routine sets things up so that the expected
  1484.  *    virtual address is accessible.
  1485.  *
  1486.  * Results:
  1487.  *      None.
  1488.  *
  1489.  * Side effects:
  1490.  *      The old pte stored at the virtual address and the page frame that is
  1491.  *    allocated are stored in static globals.
  1492.  *
  1493.  * ----------------------------------------------------------------------------
  1494.  */
  1495. /*ARGSUSED*/
  1496. void
  1497. VmMach_MapIntelPage(virtAddr) 
  1498.     Address    virtAddr; /* Virtual address where a page has to be validated
  1499.                  at. */
  1500. {
  1501. #ifdef sun2
  1502.     VmMachPTE        pte;
  1503.     int            pmeg;
  1504.  
  1505.     /*
  1506.      * See if there is a PMEG already.  If not allocate one.
  1507.      */
  1508.  
  1509.     pmeg = VmMachGetSegMap(virtAddr);
  1510.     if (pmeg == VMMACH_INV_PMEG) {
  1511.     MASTER_LOCK(vmMachMutexPtr);
  1512.     allocatedPMEG = PMEGGet(vm_SysSegPtr, 
  1513.                 (unsigned)virtAddr >> VMMACH_SEG_SHIFT,
  1514.                 PMEG_DONT_ALLOC);
  1515.     MASTER_UNLOCK(vmMachMutexPtr);
  1516.     VmMachSetSegMap(virtAddr, allocatedPMEG);
  1517.     } else {
  1518.     allocatedPMEG = VMMACH_INV_PMEG;
  1519.     intelSavedPTE = VmMachGetPageMap(virtAddr);
  1520.     }
  1521.  
  1522.     /*
  1523.      * Set up the page table entry.
  1524.      */
  1525.     intelPage = Vm_KernPageAllocate();
  1526.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(intelPage);
  1527.     VmMachSetPageMap(virtAddr, pte);
  1528. #endif
  1529. }
  1530.  
  1531.  
  1532. /*
  1533.  * ----------------------------------------------------------------------------
  1534.  *
  1535.  * Vm_UnmapIntelPage --
  1536.  *
  1537.  *      Deallocate and invalidate a page for the intel chip.  This is a special
  1538.  *    case routine that is only for the intel ethernet chip.
  1539.  *
  1540.  * Results:
  1541.  *      None.
  1542.  *
  1543.  * Side effects:
  1544.  *      The hardware segment table associated with the segment
  1545.  *      is modified to invalidate the page.
  1546.  *
  1547.  * ----------------------------------------------------------------------------
  1548.  */
  1549. /*ARGSUSED*/
  1550. void
  1551. VmMach_UnmapIntelPage(virtAddr) 
  1552.     Address    virtAddr;
  1553. {
  1554. #ifdef sun2
  1555.     if (allocatedPMEG != VMMACH_INV_PMEG) {
  1556.     /*
  1557.      * Free up the PMEG.
  1558.      */
  1559.     VmMachSetPageMap(virtAddr, (VmMachPTE)0);
  1560.     VmMachSetSegMap(virtAddr, VMMACH_INV_PMEG);
  1561.  
  1562.     MASTER_LOCK(vmMachMutexPtr);
  1563.  
  1564.     PMEGFree(allocatedPMEG);
  1565.  
  1566.     MASTER_UNLOCK(vmMachMutexPtr);
  1567.     } else {
  1568.     /*
  1569.      * Restore the saved pte and free the allocated page.
  1570.      */
  1571.     VmMachSetPageMap(virtAddr, intelSavedPTE);
  1572.     }
  1573.     Vm_KernPageFree(intelPage);
  1574. #endif
  1575. }
  1576.  
  1577. #ifdef sun3
  1578.  
  1579. static Address        netMemAddr;
  1580. static unsigned int    netLastPage;
  1581.  
  1582.  
  1583. /*
  1584.  * ----------------------------------------------------------------------------
  1585.  *
  1586.  * InitNetMem --
  1587.  *
  1588.  *      Initialize the memory mappings for the network.
  1589.  *
  1590.  * Results:
  1591.  *      None.
  1592.  *
  1593.  * Side effects:
  1594.  *      PMEGS are allocated and initialized.
  1595.  *
  1596.  * ----------------------------------------------------------------------------
  1597.  */
  1598. static void
  1599. InitNetMem()
  1600. {
  1601.     unsigned char        pmeg;
  1602.     register unsigned char    *segTablePtr;
  1603.     int                i;
  1604.     int                segNum;
  1605.     Address            virtAddr;
  1606.  
  1607.     /*
  1608.      * Allocate two pmegs, one for memory and one for mapping.
  1609.      */
  1610.     segNum = VMMACH_NET_MAP_START >> VMMACH_SEG_SHIFT;
  1611.     for (i = 0, virtAddr = (Address)VMMACH_NET_MAP_START,
  1612.         segTablePtr = GetHardSegPtr(vm_SysSegPtr->machPtr, segNum);
  1613.      i < 2;
  1614.          i++, virtAddr += VMMACH_SEG_SIZE, segNum++) {
  1615.     pmeg = VmMachGetSegMap(virtAddr);
  1616.     if (pmeg == VMMACH_INV_PMEG) {
  1617.         *(segTablePtr + i) = PMEGGet(vm_SysSegPtr, segNum, PMEG_DONT_ALLOC);
  1618.         VmMachSetSegMap(virtAddr, *(segTablePtr + i));
  1619.     }
  1620.     }
  1621.     /*
  1622.      * Propagate the new pmeg mappings to all contexts.
  1623.      */
  1624.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  1625.     if (i == VMMACH_KERN_CONTEXT) {
  1626.         continue;
  1627.     }
  1628.     VmMachSetContextReg(i);
  1629.     VmMachSetSegMap((Address)VMMACH_NET_MAP_START, *segTablePtr);
  1630.     VmMachSetSegMap((Address)(VMMACH_NET_MAP_START + VMMACH_SEG_SIZE),
  1631.             *(segTablePtr + 1));
  1632.     }
  1633.     VmMachSetContextReg(VMMACH_KERN_CONTEXT);
  1634.     netMemAddr = (Address)VMMACH_NET_MEM_START;
  1635.     netLastPage = ((unsigned)(VMMACH_NET_MEM_START) >> VMMACH_PAGE_SHIFT) - 1;
  1636. }
  1637.  
  1638. /*
  1639.  * ----------------------------------------------------------------------------
  1640.  *
  1641.  * VmMach_NetMemAlloc --
  1642.  *
  1643.  *      Allocate physical memory for a network driver.
  1644.  *
  1645.  * Results:
  1646.  *      The address where the memory is allocated at.
  1647.  *
  1648.  * Side effects:
  1649.  *      Memory allocated.
  1650.  *
  1651.  * ----------------------------------------------------------------------------
  1652.  */
  1653. Address
  1654. VmMach_NetMemAlloc(numBytes)
  1655.     int    numBytes;    /* Number of bytes of memory to allocated. */
  1656. {
  1657.     VmMachPTE    pte;
  1658.     Address    retAddr;
  1659.     Address    maxAddr;
  1660.     Address    virtAddr;
  1661.     static Boolean initialized = FALSE;
  1662.  
  1663.     if (!initialized) {
  1664.     InitNetMem();
  1665.     initialized = TRUE;
  1666.     }
  1667.  
  1668.     retAddr = netMemAddr;
  1669.     netMemAddr += (numBytes + 3) & ~3;
  1670.     /*
  1671.      * Panic if we are out of memory.  We are out of memory if we have filled
  1672.      * up a whole PMEG minus one page.  We have to leave one page at the
  1673.      * end because this is used to initialize the INTEL chip.
  1674.      */
  1675.     if (netMemAddr > (Address) (VMMACH_NET_MEM_START + VMMACH_SEG_SIZE - 
  1676.                 VMMACH_PAGE_SIZE)) {
  1677.     panic("VmMach_NetMemAlloc: Out of network memory\n");
  1678.     }
  1679.  
  1680.     maxAddr = (Address) ((netLastPage + 1) * VMMACH_PAGE_SIZE - 1);
  1681.  
  1682.     /*
  1683.      * Add new pages to the virtual address space until we have added enough
  1684.      * to handle this memory request.
  1685.      */
  1686.     while (netMemAddr - 1 > maxAddr) {
  1687.     maxAddr += VMMACH_PAGE_SIZE;
  1688.     netLastPage++;
  1689.     virtAddr = (Address) (netLastPage << VMMACH_PAGE_SHIFT);
  1690.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  1691.           VirtToPhysPage(Vm_KernPageAllocate());
  1692.     SET_ALL_PAGE_MAP(virtAddr, pte);
  1693.     }
  1694.  
  1695.     return(retAddr);
  1696. }
  1697.  
  1698.  
  1699. /*
  1700.  *----------------------------------------------------------------------
  1701.  *
  1702.  * VmMach_NetMapPacket --
  1703.  *
  1704.  *    Map the packet pointed to by the scatter-gather array.
  1705.  *
  1706.  * Results:
  1707.  *    None.
  1708.  *
  1709.  * Side effects:
  1710.  *    The outScatGathArray is filled in with pointers to where the
  1711.  *    packet was mapped in.
  1712.  *
  1713.  *----------------------------------------------------------------------
  1714.  */
  1715. void
  1716. VmMach_NetMapPacket(inScatGathPtr, scatGathLength, outScatGathPtr)
  1717.     register Net_ScatterGather    *inScatGathPtr;
  1718.     register int        scatGathLength;
  1719.     register Net_ScatterGather    *outScatGathPtr;
  1720. {
  1721.     register Address    mapAddr;
  1722.     register Address    endAddr;
  1723.  
  1724.     for (mapAddr = (Address)VMMACH_NET_MAP_START;
  1725.          scatGathLength > 0;
  1726.      scatGathLength--, inScatGathPtr++, outScatGathPtr++) {
  1727.     outScatGathPtr->length = inScatGathPtr->length;
  1728.     if (inScatGathPtr->length == 0) {
  1729.         continue;
  1730.     }
  1731.     /*
  1732.      * Map the piece of the packet in.  Note that we know that a packet
  1733.      * piece is no longer than 1536 bytes so we know that we will need
  1734.      * at most two page table entries to map a piece in.
  1735.      */
  1736.     VmMachSetPageMap(mapAddr, VmMachGetPageMap(inScatGathPtr->bufAddr));
  1737.     outScatGathPtr->bufAddr = 
  1738.         mapAddr + ((unsigned)inScatGathPtr->bufAddr & VMMACH_OFFSET_MASK);
  1739.     mapAddr += VMMACH_PAGE_SIZE_INT;
  1740.     endAddr = inScatGathPtr->bufAddr + inScatGathPtr->length - 1;
  1741.     if (((unsigned)inScatGathPtr->bufAddr & ~VMMACH_OFFSET_MASK_INT) !=
  1742.         ((unsigned)endAddr & ~VMMACH_OFFSET_MASK_INT)) {
  1743.         VmMachSetPageMap(mapAddr, VmMachGetPageMap(endAddr));
  1744.         mapAddr += VMMACH_PAGE_SIZE_INT;
  1745.     }
  1746.     }
  1747. }
  1748.  
  1749. #endif
  1750.  
  1751.  
  1752. /*
  1753.  *----------------------------------------------------------------------
  1754.  *
  1755.  * VmMach_VirtAddrParse --
  1756.  *
  1757.  *    See if the given address falls into the special mapping segment.
  1758.  *    If so parse it for our caller.
  1759.  *
  1760.  * Results:
  1761.  *    TRUE if the address fell into the special mapping segment, FALSE
  1762.  *    otherwise.
  1763.  *
  1764.  * Side effects:
  1765.  *    *transVirtAddrPtr may be filled in.
  1766.  *
  1767.  *----------------------------------------------------------------------
  1768.  */
  1769. Boolean
  1770. VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  1771.     Proc_ControlBlock        *procPtr;
  1772.     Address            virtAddr;
  1773.     register    Vm_VirtAddr    *transVirtAddrPtr;
  1774. {
  1775.     Address    origVirtAddr;
  1776.     Boolean    retVal;
  1777.  
  1778.     if (virtAddr >= (Address)VMMACH_MAP_SEG_ADDR && 
  1779.         virtAddr < (Address)mach_KernStart) {
  1780.     /*
  1781.      * The address falls into the special mapping segment.  Translate
  1782.      * the address back to the segment that it falls into.
  1783.      */
  1784.     transVirtAddrPtr->segPtr = procPtr->vmPtr->machPtr->mapSegPtr;
  1785.     origVirtAddr = 
  1786.         (Address)(procPtr->vmPtr->machPtr->mapHardSeg << VMMACH_SEG_SHIFT);
  1787.     transVirtAddrPtr->sharedPtr = procPtr->vmPtr->machPtr->sharedPtr;
  1788.     if (transVirtAddrPtr->segPtr->type == VM_SHARED) {
  1789.         origVirtAddr += ((segOffset(transVirtAddrPtr)-
  1790.             transVirtAddrPtr->segPtr->offset)
  1791.             >>(VMMACH_SEG_SHIFT-VMMACH_PAGE_SHIFT))
  1792.             << VMMACH_SEG_SHIFT;
  1793.     }
  1794.     if (debugVmStubs) {
  1795.         printf("segOffset = %x, offset = %x, mapHardSeg = %x\n",
  1796.             segOffset(transVirtAddrPtr),
  1797.             transVirtAddrPtr->segPtr->offset,
  1798.             procPtr->vmPtr->machPtr->mapHardSeg);
  1799.     }
  1800.     origVirtAddr += (unsigned int)virtAddr & (VMMACH_SEG_SIZE - 1);
  1801.     transVirtAddrPtr->page = (unsigned) (origVirtAddr) >> VMMACH_PAGE_SHIFT;
  1802.     transVirtAddrPtr->offset = (unsigned)virtAddr & VMMACH_OFFSET_MASK;
  1803.     transVirtAddrPtr->flags = USING_MAPPED_SEG;
  1804.     retVal = TRUE;
  1805.     } else {
  1806.     retVal = FALSE;
  1807.     }
  1808.     return(retVal);
  1809. }
  1810.  
  1811. static void    WriteHardMapSeg();
  1812.  
  1813.  
  1814. /*
  1815.  *----------------------------------------------------------------------
  1816.  *
  1817.  * VmMach_CopyInProc --
  1818.  *
  1819.  *    Copy from another processes address space into the current address
  1820.  *    space.   This is done by mapping the other processes segment into
  1821.  *    the current VAS and then doing the copy.  It assumed that this 
  1822.  *    routine is called with the source process locked such that its
  1823.  *    VM will not go away while we are doing this copy.
  1824.  *
  1825.  * Results:
  1826.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  1827.  *
  1828.  * Side effects:
  1829.  *    What toAddr points to is modified.
  1830.  *
  1831.  *----------------------------------------------------------------------
  1832.  */
  1833. /*ARGSUSED*/
  1834. ReturnStatus
  1835. VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr, virtAddrPtr,
  1836.           toAddr, toKernel)
  1837.     int     numBytes;        /* The maximum number of bytes to 
  1838.                        copy in. */
  1839.     Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  1840.     Address        fromAddr;    /* The address to copy from */
  1841.     Vm_VirtAddr        *virtAddrPtr;
  1842.     Address        toAddr;        /* The address to copy to */
  1843.     Boolean        toKernel;    /* This copy is happening to the
  1844.                      * kernel's address space. */
  1845. {
  1846.     ReturnStatus        status = SUCCESS;
  1847.     register VmMach_ProcData    *machPtr;
  1848.     Proc_ControlBlock        *toProcPtr;
  1849.     int                segOffset;
  1850.     int                bytesToCopy;
  1851.  
  1852.     toProcPtr = Proc_GetCurrentProc();
  1853.     machPtr = toProcPtr->vmPtr->machPtr;
  1854.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  1855.     machPtr->mapHardSeg = (unsigned int) (fromAddr) >> VMMACH_SEG_SHIFT;
  1856.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  1857.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  1858.     /*
  1859.      * Mangle the segment offset so that it matches the offset
  1860.      * of the mapped segment.
  1861.      */
  1862.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  1863.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  1864.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  1865.     }
  1866.     /*
  1867.      * Do a hardware segments worth at a time until done.
  1868.      */
  1869.     while (numBytes > 0 && status == SUCCESS) {
  1870.     segOffset = (unsigned int)fromAddr & (VMMACH_SEG_SIZE - 1);
  1871.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  1872.     if (bytesToCopy > numBytes) {
  1873.         bytesToCopy = numBytes;
  1874.     }
  1875.     /*
  1876.      * Push out the hardware segment.
  1877.      */
  1878.     WriteHardMapSeg(machPtr);
  1879.     /*
  1880.      * Do the copy.
  1881.      */
  1882.     toProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  1883.     status = VmMachDoCopy(bytesToCopy,
  1884.                   (Address)(VMMACH_MAP_SEG_ADDR + segOffset),
  1885.                   toAddr);
  1886.     toProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  1887.     if (status == SUCCESS) {
  1888.         numBytes -= bytesToCopy;
  1889.         fromAddr += bytesToCopy;
  1890.         toAddr += bytesToCopy;
  1891.     } else {
  1892.         status = SYS_ARG_NOACCESS;
  1893.     }
  1894.     /*
  1895.      * Zap the hardware segment.
  1896.      */
  1897.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  1898.     machPtr->mapHardSeg++;
  1899.     }
  1900.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1901.     return(status);
  1902. }
  1903.  
  1904.  
  1905. /*
  1906.  *----------------------------------------------------------------------
  1907.  *
  1908.  * VmMach_CopyOutProc --
  1909.  *
  1910.  *    Copy from the current VAS to another processes VAS.  This is done by 
  1911.  *    mapping the other processes segment into the current VAS and then 
  1912.  *    doing the copy.  It assumed that this routine is called with the dest
  1913.  *    process locked such that its VM will not go away while we are doing
  1914.  *    the copy.
  1915.  *
  1916.  * Results:
  1917.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  1918.  *
  1919.  * Side effects:
  1920.  *    What toAddr points to is modified.
  1921.  *
  1922.  *----------------------------------------------------------------------
  1923.  */
  1924. /*ARGSUSED*/
  1925. ReturnStatus
  1926. VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr,
  1927.            virtAddrPtr)
  1928.     int         numBytes;    /* The maximum number of bytes to 
  1929.                        copy in. */
  1930.     Address        fromAddr;    /* The address to copy from */
  1931.     Boolean        fromKernel;    /* This copy is happening to the
  1932.                      * kernel's address space. */
  1933.     Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  1934.     Address        toAddr;        /* The address to copy to */
  1935.     Vm_VirtAddr        *virtAddrPtr;
  1936. {
  1937.     ReturnStatus        status = SUCCESS;
  1938.     register VmMach_ProcData    *machPtr;
  1939.     Proc_ControlBlock        *fromProcPtr;
  1940.     int                segOffset;
  1941.     int                bytesToCopy;
  1942.  
  1943.  
  1944.     fromProcPtr = Proc_GetCurrentProc();
  1945.     machPtr = fromProcPtr->vmPtr->machPtr;
  1946.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  1947.     machPtr->mapHardSeg = (unsigned int) (toAddr) >> VMMACH_SEG_SHIFT;
  1948.     machPtr->sharedPtr = virtAddrPtr->sharedPtr;
  1949.     if (virtAddrPtr->sharedPtr != (Vm_SegProcList*)NIL) {
  1950.     /*
  1951.      * Mangle the segment offset so that it matches the offset
  1952.      * of the mapped segment.
  1953.      */
  1954.     machPtr->mapHardSeg -= (virtAddrPtr->sharedPtr->offset<<
  1955.         VMMACH_PAGE_SHIFT_INT)>>VMMACH_SEG_SHIFT;
  1956.     machPtr->mapHardSeg += machPtr->mapSegPtr->machPtr->offset;
  1957.     }
  1958.     /*
  1959.      * Do a hardware segments worth at a time until done.
  1960.      */
  1961.     while (numBytes > 0 && status == SUCCESS) {
  1962.     segOffset = (unsigned int)toAddr & (VMMACH_SEG_SIZE - 1);
  1963.     bytesToCopy = VMMACH_SEG_SIZE - segOffset;
  1964.     if (bytesToCopy > numBytes) {
  1965.         bytesToCopy = numBytes;
  1966.     }
  1967.     /*
  1968.      * Push out the hardware segment.
  1969.      */
  1970.     WriteHardMapSeg(machPtr);
  1971.     /*
  1972.      * Do the copy.
  1973.      */
  1974.     fromProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  1975.     status = VmMachDoCopy(bytesToCopy, fromAddr,
  1976.               (Address) (VMMACH_MAP_SEG_ADDR + segOffset));
  1977.     fromProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  1978.     if (status == SUCCESS) {
  1979.         numBytes -= bytesToCopy;
  1980.         fromAddr += bytesToCopy;
  1981.         toAddr += bytesToCopy;
  1982.     } else {
  1983.         status = SYS_ARG_NOACCESS;
  1984.     }
  1985.     /*
  1986.      * Zap the hardware segment.
  1987.      */
  1988.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, VMMACH_INV_PMEG); 
  1989.  
  1990.     machPtr->mapHardSeg++;
  1991.     }
  1992.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  1993.     return(status);
  1994. }
  1995.  
  1996.  
  1997. /*
  1998.  *----------------------------------------------------------------------
  1999.  *
  2000.  * WriteHardMapSeg --
  2001.  *
  2002.  *    Push the hardware segment map entry out to the hardware for the
  2003.  *    given mapped segment.
  2004.  *
  2005.  * Results:
  2006.  *    None.
  2007.  *
  2008.  * Side effects:
  2009.  *    Hardware segment modified.
  2010.  *
  2011.  *----------------------------------------------------------------------
  2012.  */
  2013. ENTRY static void
  2014. WriteHardMapSeg(machPtr)
  2015.     VmMach_ProcData    *machPtr;
  2016. {
  2017.     MASTER_LOCK(vmMachMutexPtr);
  2018.  
  2019.     if (machPtr->contextPtr != (VmMach_Context *) NIL) {
  2020.         machPtr->contextPtr->map[MAP_SEG_NUM] =
  2021.             (int)*GetHardSegPtr(machPtr->mapSegPtr->machPtr,
  2022.             machPtr->mapHardSeg);
  2023.     }
  2024.     VmMachSetSegMap((Address)VMMACH_MAP_SEG_ADDR, 
  2025.      *GetHardSegPtr(machPtr->mapSegPtr->machPtr, machPtr->mapHardSeg));
  2026.  
  2027.     MASTER_UNLOCK(vmMachMutexPtr);
  2028. }
  2029.  
  2030.  
  2031. /*
  2032.  *----------------------------------------------------------------------
  2033.  *
  2034.  * VmMach_SetSegProt --
  2035.  *
  2036.  *    Change the protection in the page table for the given range of bytes
  2037.  *    for the given segment.
  2038.  *
  2039.  * Results:
  2040.  *    None.
  2041.  *
  2042.  * Side effects:
  2043.  *    Page table may be modified for the segment.
  2044.  *
  2045.  *----------------------------------------------------------------------
  2046.  */
  2047. ENTRY void
  2048. VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable)
  2049.     register Vm_Segment        *segPtr;    /* Segment to change protection
  2050.                            for. */
  2051.     register int        firstPage;  /* First page to set protection
  2052.                          * for. */
  2053.     int                lastPage;   /* First page to set protection
  2054.                          * for. */
  2055.     Boolean            makeWriteable;/* TRUE => make the pages 
  2056.                            *     writable.
  2057.                            * FALSE => make readable only.*/
  2058. {
  2059.     register    VmMachPTE    pte;
  2060.     register    Address        virtAddr;
  2061.     register    unsigned char    *pmegNumPtr;
  2062.     register    PMEG        *pmegPtr;
  2063.     register    Boolean        skipSeg = FALSE;
  2064.     Boolean            nextSeg = TRUE;
  2065.     Address            tVirtAddr;
  2066.     Address            pageVirtAddr;
  2067.     int                i;
  2068.  
  2069.     MASTER_LOCK(vmMachMutexPtr);
  2070.  
  2071.     pmegNumPtr = GetHardSegPtr(segPtr->machPtr, PageToSeg(firstPage)) - 1;
  2072.     virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  2073.     while (firstPage <= lastPage) {
  2074.     if (nextSeg) {
  2075.         pmegNumPtr++;
  2076.         if (*pmegNumPtr != VMMACH_INV_PMEG) {
  2077.         pmegPtr = &pmegArray[*pmegNumPtr];
  2078.         if (pmegPtr->pageCount != 0) {
  2079.             VmMachSetSegMap(vmMachPTESegAddr, *pmegNumPtr);
  2080.             skipSeg = FALSE;
  2081.         } else {
  2082.             skipSeg = TRUE;
  2083.         }
  2084.         } else {
  2085.         skipSeg = TRUE;
  2086.         }
  2087.         nextSeg = FALSE;
  2088.     }
  2089.     if (!skipSeg) {
  2090.         /*
  2091.          * Change the hardware page table.
  2092.          */
  2093.         tVirtAddr =
  2094.         ((unsigned int)virtAddr & VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2095.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++) {
  2096.         pageVirtAddr = tVirtAddr + i * VMMACH_PAGE_SIZE_INT;
  2097.         pte = VmMachGetPageMap(pageVirtAddr);
  2098.         if (pte & VMMACH_RESIDENT_BIT) {
  2099.             Vm_TracePTEChange    pteChange;
  2100.             if (vm_Tracing) {
  2101.             pteChange.changeType = VM_TRACE_SET_SEG_PROT;
  2102.             pteChange.segNum = segPtr->segNum;
  2103.             pteChange.pageNum = firstPage;
  2104.             pteChange.softPTE = FALSE;
  2105.             pteChange.beforePTE = pte;
  2106.             }
  2107.             pte &= ~VMMACH_PROTECTION_FIELD;
  2108.             pte |= makeWriteable ? VMMACH_URW_PROT : VMMACH_UR_PROT;
  2109.             if (vm_Tracing) {
  2110.             pteChange.afterPTE = pte;
  2111.             VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  2112.                      sizeof(Vm_TracePTEChange),
  2113.                      (Address)&pteChange, TRUE);
  2114.             }
  2115.             VmMachSetPageMap(pageVirtAddr, pte);
  2116.         }
  2117.         }
  2118.         virtAddr += VMMACH_PAGE_SIZE;
  2119.         firstPage++;
  2120.         if (((unsigned int)virtAddr & VMMACH_PAGE_MASK) == 0) {
  2121.         nextSeg = TRUE;
  2122.         }
  2123.     } else {
  2124.         int    segNum;
  2125.  
  2126.         segNum = PageToSeg(firstPage) + 1;
  2127.         firstPage = SegToPage(segNum);
  2128.         virtAddr = (Address)(firstPage << VMMACH_PAGE_SHIFT);
  2129.         nextSeg = TRUE;
  2130.     }
  2131.     }
  2132.  
  2133.     MASTER_UNLOCK(vmMachMutexPtr);
  2134. }
  2135.  
  2136.  
  2137. /*
  2138.  *----------------------------------------------------------------------
  2139.  *
  2140.  * VmMach_SetPageProt --
  2141.  *
  2142.  *    Set the protection in hardware and software for the given virtual
  2143.  *    page.
  2144.  *
  2145.  * Results:
  2146.  *    None.
  2147.  *
  2148.  * Side effects:
  2149.  *    Page table may be modified for the segment.
  2150.  *
  2151.  *----------------------------------------------------------------------
  2152.  */
  2153. ENTRY void
  2154. VmMach_SetPageProt(virtAddrPtr, softPTE)
  2155.     register    Vm_VirtAddr    *virtAddrPtr;    /* The virtual page to set the
  2156.                          * protection for.*/
  2157.     Vm_PTE            softPTE;    /* Software pte. */
  2158. {
  2159.     register    VmMachPTE     hardPTE;
  2160.     register    VmMach_SegData    *machPtr;
  2161.     Address               virtAddr;
  2162.     int                pmegNum;
  2163.     int                i;
  2164.     Vm_TracePTEChange        pteChange;
  2165.  
  2166.     MASTER_LOCK(vmMachMutexPtr);
  2167.  
  2168.     machPtr = virtAddrPtr->segPtr->machPtr;
  2169.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2170.         virtAddrPtr));
  2171.     if (pmegNum != VMMACH_INV_PMEG) {
  2172.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  2173.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;    
  2174.     for (i = 0; 
  2175.          i < VMMACH_CLUSTER_SIZE; 
  2176.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2177.         hardPTE = VmMachReadPTE(pmegNum, virtAddr);
  2178.         if (vm_Tracing) {
  2179.         pteChange.changeType = VM_TRACE_SET_PAGE_PROT;
  2180.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  2181.         pteChange.pageNum = virtAddrPtr->page;
  2182.         pteChange.softPTE = FALSE;
  2183.         pteChange.beforePTE = hardPTE;
  2184.         }
  2185.         hardPTE &= ~VMMACH_PROTECTION_FIELD;
  2186.         hardPTE |= (softPTE & (VM_COW_BIT | VM_READ_ONLY_PROT)) ? 
  2187.                     VMMACH_UR_PROT : VMMACH_URW_PROT;
  2188.         if (vm_Tracing) {
  2189.         pteChange.afterPTE = hardPTE;
  2190.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  2191.                  sizeof(Vm_TracePTEChange), 
  2192.                  (Address)&pteChange, TRUE);
  2193.         }
  2194.         VmMachWritePTE(pmegNum, virtAddr, hardPTE);
  2195.     }
  2196.     }
  2197.  
  2198.     MASTER_UNLOCK(vmMachMutexPtr);
  2199. }
  2200.  
  2201.  
  2202. /*
  2203.  * ----------------------------------------------------------------------------
  2204.  *
  2205.  * VmMach_AllocCheck --
  2206.  *
  2207.  *      Determine if this page can be reallocated.  A page can be reallocated
  2208.  *    if it has not been referenced or modified.
  2209.  *  
  2210.  * Results:
  2211.  *      None.
  2212.  *
  2213.  * Side effects:
  2214.  *      The given page will be invalidated in the hardware if it has not
  2215.  *    been referenced and *refPtr and *modPtr will have the hardware 
  2216.  *    reference and modify bits or'd in.
  2217.  *
  2218.  * ----------------------------------------------------------------------------
  2219.  */
  2220. ENTRY void
  2221. VmMach_AllocCheck(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  2222.     register    Vm_VirtAddr    *virtAddrPtr;
  2223.     unsigned    int        virtFrameNum;
  2224.     register    Boolean        *refPtr;
  2225.     register    Boolean        *modPtr;
  2226. {
  2227.     register VmMach_SegData    *machPtr;
  2228.     register VmMachPTE         hardPTE;  
  2229.     int                pmegNum; 
  2230.     Address            virtAddr;
  2231.     int                i;
  2232.     int                origMod;
  2233.  
  2234.     MASTER_LOCK(vmMachMutexPtr);
  2235.  
  2236.     origMod = *modPtr;
  2237.  
  2238.     *refPtr |= refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  2239.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  2240.     if (!*refPtr || !*modPtr) {
  2241.     machPtr = virtAddrPtr->segPtr->machPtr;
  2242.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2243.         virtAddrPtr));
  2244.     if (pmegNum != VMMACH_INV_PMEG) {
  2245.         hardPTE = 0;
  2246.         virtAddr = 
  2247.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  2248.             vmMachPTESegAddr;
  2249.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  2250.         hardPTE |= VmMachReadPTE(pmegNum, 
  2251.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  2252.         }
  2253.         *refPtr |= hardPTE & VMMACH_REFERENCED_BIT;
  2254.         *modPtr |= hardPTE & VMMACH_MODIFIED_BIT;
  2255.     }
  2256.     }
  2257.     if (!*refPtr) {
  2258.     /*
  2259.      * Invalidate the page so that it will force a fault if it is
  2260.      * referenced.  Since our caller has blocked all faults on this
  2261.      * page, by invalidating it we can guarantee that the reference and
  2262.      * modify information that we are returning will be valid until
  2263.      * our caller reenables faults on this page.
  2264.      */
  2265.     PageInvalidate(virtAddrPtr, virtFrameNum, FALSE);
  2266.  
  2267.     if (origMod && !*modPtr) {
  2268.         /*
  2269.          * This page had the modify bit set in software but not in
  2270.          * hardware.
  2271.          */
  2272.         vmStat.notHardModPages++;
  2273.     }
  2274.     }
  2275.     *modPtr |= origMod;
  2276.  
  2277.     MASTER_UNLOCK(vmMachMutexPtr);
  2278.  
  2279. }
  2280.  
  2281.  
  2282. /*
  2283.  * ----------------------------------------------------------------------------
  2284.  *
  2285.  * VmMach_GetRefModBits --
  2286.  *
  2287.  *      Pull the reference and modified bits out of hardware.
  2288.  *  
  2289.  * Results:
  2290.  *      None.
  2291.  *
  2292.  * Side effects:
  2293.  *      
  2294.  *
  2295.  * ----------------------------------------------------------------------------
  2296.  */
  2297. ENTRY void
  2298. VmMach_GetRefModBits(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  2299.     register    Vm_VirtAddr    *virtAddrPtr;
  2300.     unsigned    int        virtFrameNum;
  2301.     register    Boolean        *refPtr;
  2302.     register    Boolean        *modPtr;
  2303. {
  2304.     register VmMach_SegData    *machPtr;
  2305.     register VmMachPTE         hardPTE;  
  2306.     int                pmegNum; 
  2307.     Address            virtAddr;
  2308.     int                i;
  2309.  
  2310.     MASTER_LOCK(vmMachMutexPtr);
  2311.  
  2312.     *refPtr = refModMap[virtFrameNum] & VMMACH_REFERENCED_BIT;
  2313.     *modPtr = refModMap[virtFrameNum] & VMMACH_MODIFIED_BIT;
  2314.     if (!*refPtr || !*modPtr) {
  2315.     machPtr = virtAddrPtr->segPtr->machPtr;
  2316.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2317.         virtAddrPtr));
  2318.     if (pmegNum != VMMACH_INV_PMEG) {
  2319.         hardPTE = 0;
  2320.         virtAddr = 
  2321.         ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & VMMACH_PAGE_MASK) + 
  2322.             vmMachPTESegAddr;
  2323.         for (i = 0; i < VMMACH_CLUSTER_SIZE; i++ ) {
  2324.         hardPTE |= VmMachReadPTE(pmegNum, 
  2325.                     virtAddr + i * VMMACH_PAGE_SIZE_INT);
  2326.         }
  2327.         if (!*refPtr) {
  2328.         *refPtr = hardPTE & VMMACH_REFERENCED_BIT;
  2329.         }
  2330.         if (!*modPtr) {
  2331.         *modPtr = hardPTE & VMMACH_MODIFIED_BIT;
  2332.         }
  2333.     }
  2334.     }
  2335.  
  2336.     MASTER_UNLOCK(vmMachMutexPtr);
  2337.  
  2338. }
  2339.  
  2340.  
  2341. /*
  2342.  * ----------------------------------------------------------------------------
  2343.  *
  2344.  * VmMach_ClearRefBit --
  2345.  *
  2346.  *      Clear the reference bit at the given virtual address.
  2347.  *
  2348.  * Results:
  2349.  *      None.
  2350.  *
  2351.  * Side effects:
  2352.  *      Hardware reference bit cleared.
  2353.  *
  2354.  * ----------------------------------------------------------------------------
  2355.  */
  2356. ENTRY void
  2357. VmMach_ClearRefBit(virtAddrPtr, virtFrameNum)
  2358.     register    Vm_VirtAddr    *virtAddrPtr;
  2359.     unsigned     int        virtFrameNum;
  2360. {
  2361.     register    VmMach_SegData    *machPtr;
  2362.     int                pmegNum;
  2363.     Address            virtAddr;
  2364.     int                i;
  2365.     VmMachPTE            pte;
  2366.     Vm_TracePTEChange        pteChange;
  2367.  
  2368.     MASTER_LOCK(vmMachMutexPtr);
  2369.  
  2370.     refModMap[virtFrameNum] &= ~VMMACH_REFERENCED_BIT;
  2371.     machPtr = virtAddrPtr->segPtr->machPtr;
  2372.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2373.         virtAddrPtr));
  2374.     if (pmegNum != VMMACH_INV_PMEG) {
  2375.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  2376.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2377.     for (i = 0; 
  2378.          i < VMMACH_CLUSTER_SIZE;
  2379.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2380.         pte = VmMachReadPTE(pmegNum, virtAddr);
  2381.         if (vm_Tracing) {
  2382.         pteChange.changeType = VM_TRACE_CLEAR_REF_BIT;
  2383.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  2384.         pteChange.pageNum = virtAddrPtr->page;
  2385.         pteChange.softPTE = FALSE;
  2386.         pteChange.beforePTE = pte;
  2387.         pteChange.afterPTE = pte & ~VMMACH_REFERENCED_BIT;
  2388.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  2389.                  sizeof(Vm_TracePTEChange), 
  2390.                  (Address)&pteChange, TRUE);
  2391.         }
  2392.         pte &= ~VMMACH_REFERENCED_BIT;
  2393.         VmMachWritePTE(pmegNum, virtAddr, pte);
  2394.     }
  2395.     }
  2396.  
  2397.     MASTER_UNLOCK(vmMachMutexPtr);
  2398. }
  2399.  
  2400.  
  2401. /*
  2402.  * ----------------------------------------------------------------------------
  2403.  *
  2404.  * VmMach_ClearModBit --
  2405.  *
  2406.  *      Clear the modified bit at the given virtual address.
  2407.  *
  2408.  * Results:
  2409.  *      None.
  2410.  *
  2411.  * Side effects:
  2412.  *      Hardware modified bit cleared.
  2413.  *
  2414.  * ----------------------------------------------------------------------------
  2415.  */
  2416. ENTRY void
  2417. VmMach_ClearModBit(virtAddrPtr, virtFrameNum)
  2418.     register    Vm_VirtAddr    *virtAddrPtr;
  2419.     unsigned    int        virtFrameNum;
  2420. {
  2421.     register    VmMach_SegData    *machPtr;
  2422.     int                pmegNum;
  2423.     Address            virtAddr;
  2424.     int                i;
  2425.     Vm_PTE            pte;
  2426.     Vm_TracePTEChange        pteChange;
  2427.  
  2428.     MASTER_LOCK(vmMachMutexPtr);
  2429.  
  2430.     refModMap[virtFrameNum] &= ~VMMACH_MODIFIED_BIT;
  2431.     machPtr = virtAddrPtr->segPtr->machPtr;
  2432.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2433.         virtAddrPtr));
  2434.     if (pmegNum != VMMACH_INV_PMEG) {
  2435.     virtAddr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) & 
  2436.             VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2437.     for (i = 0; 
  2438.          i < VMMACH_CLUSTER_SIZE; 
  2439.          i++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2440.         pte = VmMachReadPTE(pmegNum, virtAddr);
  2441.         if (vm_Tracing) {
  2442.         pteChange.changeType = VM_TRACE_CLEAR_MOD_BIT;
  2443.         pteChange.segNum = virtAddrPtr->segPtr->segNum;
  2444.         pteChange.pageNum = virtAddrPtr->page;
  2445.         pteChange.softPTE = FALSE;
  2446.         pteChange.beforePTE = pte;
  2447.         pteChange.afterPTE = pte & ~VMMACH_MODIFIED_BIT;
  2448.         VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  2449.                 sizeof(Vm_TracePTEChange), 
  2450.                 (Address)&pteChange, TRUE);
  2451.         }
  2452.         pte &= ~VMMACH_MODIFIED_BIT;
  2453.         VmMachWritePTE(pmegNum, virtAddr, pte);
  2454.     }
  2455.     }
  2456.  
  2457.     MASTER_UNLOCK(vmMachMutexPtr);
  2458. }
  2459.  
  2460.  
  2461. /*
  2462.  * ----------------------------------------------------------------------------
  2463.  *
  2464.  * VmMach_PageValidate --
  2465.  *
  2466.  *      Validate a page for the given virtual address.  It is assumed that when
  2467.  *      this routine is called that the user context register contains the
  2468.  *    context in which the page will be validated.
  2469.  *
  2470.  * Results:
  2471.  *      None.
  2472.  *
  2473.  * Side effects:
  2474.  *      The page table and hardware segment tables associated with the segment
  2475.  *      are modified to validate the page.
  2476.  *
  2477.  * ----------------------------------------------------------------------------
  2478.  */
  2479. ENTRY void
  2480. VmMach_PageValidate(virtAddrPtr, pte) 
  2481.     register    Vm_VirtAddr    *virtAddrPtr;
  2482.     Vm_PTE            pte;
  2483. {
  2484.     register  Vm_Segment    *segPtr;
  2485.     register  unsigned  char    *segTablePtr;
  2486.     register  PMEG        *pmegPtr;
  2487.     register  int        hardSeg;
  2488.     register  int        newPMEG;
  2489.     register  VmMachPTE        hardPTE;
  2490.     register  VmMachPTE        tHardPTE;
  2491.     Address            addr;
  2492.     int                i;
  2493.  
  2494.     MASTER_LOCK(vmMachMutexPtr);
  2495.  
  2496.     segPtr = virtAddrPtr->segPtr;
  2497.     addr = (Address) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  2498.  
  2499.     /*
  2500.      * Find out the hardware segment that has to be mapped.
  2501.      */
  2502.     hardSeg = PageToOffSeg(virtAddrPtr->page,virtAddrPtr);
  2503.     segTablePtr = GetHardSegPtr(segPtr->machPtr, hardSeg);
  2504.  
  2505.     if (*segTablePtr == VMMACH_INV_PMEG) {
  2506.     /*
  2507.      * If there is not already a pmeg for this hardware segment, then get
  2508.      * one and initialize it.  If this is for the kernel then make
  2509.      * sure that the pmeg cannot be taken away from the kernel.
  2510.      */
  2511.     if (segPtr == vm_SysSegPtr) {
  2512.         newPMEG = PMEGGet(segPtr, hardSeg, PMEG_DONT_ALLOC);
  2513.     } else {
  2514.         newPMEG = PMEGGet(segPtr, hardSeg, 0);
  2515.     }
  2516.         *segTablePtr = newPMEG;
  2517.     } else {
  2518.     pmegPtr = &pmegArray[*segTablePtr];
  2519.     if (pmegPtr->pageCount == 0) {
  2520.         /*
  2521.          * We are using a PMEG that had a pagecount of 0.  In this case
  2522.          * it was put onto the end of the free pmeg list in anticipation
  2523.          * of someone stealing this empty pmeg.  Now we have to move
  2524.          * it off of the free list.
  2525.          */
  2526.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  2527.         List_Remove((List_Links *)pmegPtr);
  2528.         } else {
  2529.         List_Move((List_Links *)pmegPtr, LIST_ATREAR(pmegInuseList));
  2530.         }
  2531.     }
  2532.     }
  2533.     hardPTE = VMMACH_RESIDENT_BIT | VirtToPhysPage(Vm_GetPageFrame(pte));
  2534.     if (segPtr == vm_SysSegPtr) {
  2535.     int    oldContext;
  2536.     /*
  2537.      * Have to propagate the PMEG to all contexts.
  2538.      */
  2539.     oldContext = VmMachGetContextReg();
  2540.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2541.         VmMachSetContextReg(i);
  2542.         VmMachSetSegMap(addr, *segTablePtr);
  2543.     }
  2544.     VmMachSetContextReg(oldContext);
  2545.     hardPTE |= VMMACH_KRW_PROT;
  2546.     } else {
  2547.     Proc_ControlBlock    *procPtr;
  2548.         VmProcLink              *procLinkPtr;
  2549.         VmMach_Context          *contextPtr;
  2550.  
  2551.     procPtr = Proc_GetCurrentProc();
  2552.     if (virtAddrPtr->flags & USING_MAPPED_SEG) {
  2553.         addr = (Address) (VMMACH_MAP_SEG_ADDR + 
  2554.                 ((unsigned int)addr & (VMMACH_SEG_SIZE - 1)));
  2555.             /* PUT IT IN SOFTWARE OF MAP AREA FOR PROCESS */
  2556.             procPtr->vmPtr->machPtr->contextPtr->map[MAP_SEG_NUM] =
  2557.                     *segTablePtr;
  2558.         } else{
  2559.             /* update it for regular seg num */
  2560.             procPtr->vmPtr->machPtr->contextPtr->map[hardSeg] = *segTablePtr;
  2561.         }
  2562.     VmMachSetSegMap(addr, *segTablePtr);
  2563.         if (segPtr != (Vm_Segment *) NIL) {
  2564.             VmCheckListIntegrity((List_Links *)segPtr->procList);
  2565.             LIST_FORALL(segPtr->procList, (List_Links *)procLinkPtr) {
  2566.                 if (procLinkPtr->procPtr->vmPtr != (Vm_ProcInfo *) NIL &&
  2567.                         procLinkPtr->procPtr->vmPtr->machPtr !=
  2568.                         (VmMach_ProcData *) NIL &&
  2569.                         (contextPtr =
  2570.                         procLinkPtr->procPtr->vmPtr->machPtr->contextPtr) !=
  2571.                         (VmMach_Context *) NIL) {
  2572.                     contextPtr->map[hardSeg] = *segTablePtr;
  2573.                 }
  2574.             }
  2575.         }
  2576.  
  2577.  
  2578.     if ((pte & (VM_COW_BIT | VM_READ_ONLY_PROT)) ||
  2579.         (virtAddrPtr->flags & VM_READONLY_SEG)) {
  2580.         hardPTE |= VMMACH_UR_PROT;
  2581.     } else {
  2582.         hardPTE |= VMMACH_URW_PROT;
  2583.     }
  2584.     }
  2585.     tHardPTE = VmMachGetPageMap(addr);
  2586.     if (tHardPTE & VMMACH_RESIDENT_BIT) {
  2587.     hardPTE |= tHardPTE & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  2588.     for (i = 1; i < VMMACH_CLUSTER_SIZE; i++ ) {
  2589.         hardPTE |= VmMachGetPageMap(addr + i * VMMACH_PAGE_SIZE_INT) & 
  2590.                 (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  2591.     }
  2592.     } else {
  2593.     pmegArray[*segTablePtr].pageCount++;
  2594.     }
  2595.     if (vm_Tracing) {
  2596.     Vm_TracePTEChange    pteChange;
  2597.  
  2598.     pteChange.changeType = VM_TRACE_VALIDATE_PAGE;
  2599.     pteChange.segNum = segPtr->segNum;
  2600.     pteChange.pageNum = virtAddrPtr->page;
  2601.     pteChange.softPTE = FALSE;
  2602.     if (tHardPTE & VMMACH_RESIDENT_BIT) {
  2603.         pteChange.beforePTE = tHardPTE;
  2604.     } else {
  2605.         pteChange.beforePTE = 0;
  2606.     }
  2607.     pteChange.afterPTE = hardPTE;
  2608.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC,
  2609.             sizeof(Vm_TracePTEChange), 
  2610.             (Address)&pteChange, TRUE);
  2611.     }
  2612.  
  2613.     SET_ALL_PAGE_MAP(addr, hardPTE);
  2614.  
  2615.     MASTER_UNLOCK(vmMachMutexPtr);
  2616. }
  2617.  
  2618.  
  2619. /*
  2620.  * ----------------------------------------------------------------------------
  2621.  *
  2622.  * PageInvalidate --
  2623.  *
  2624.  *      Invalidate a page for the given segment.  
  2625.  *
  2626.  * Results:
  2627.  *      None.
  2628.  *
  2629.  * Side effects:
  2630.  *      The page table and hardware segment tables associated with the segment
  2631.  *      are modified to invalidate the page.
  2632.  *
  2633.  * ----------------------------------------------------------------------------
  2634.  */
  2635. INTERNAL void
  2636. PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  2637.     register    Vm_VirtAddr    *virtAddrPtr;
  2638.     unsigned     int        virtPage;
  2639.     Boolean            segDeletion;
  2640. {
  2641.     register VmMach_SegData    *machPtr;
  2642.     register PMEG        *pmegPtr;
  2643.     VmMachPTE            hardPTE;
  2644.     int                pmegNum;
  2645.     Address            addr;
  2646.     int                i;
  2647.     Vm_TracePTEChange        pteChange;
  2648.  
  2649.     refModMap[virtPage] = 0;
  2650.     if (segDeletion) {
  2651.     return;
  2652.     }
  2653.     machPtr = virtAddrPtr->segPtr->machPtr;
  2654.     pmegNum = *GetHardSegPtr(machPtr, PageToOffSeg(virtAddrPtr->page,
  2655.         virtAddrPtr));
  2656.     if (pmegNum == VMMACH_INV_PMEG) {
  2657.     return;
  2658.     }
  2659.     addr = ((virtAddrPtr->page << VMMACH_PAGE_SHIFT) &
  2660.                 VMMACH_PAGE_MASK) + vmMachPTESegAddr;
  2661.     hardPTE = VmMachReadPTE(pmegNum, addr);
  2662.     if (vm_Tracing) {
  2663.     pteChange.changeType = VM_TRACE_INVALIDATE_PAGE;
  2664.     pteChange.segNum = virtAddrPtr->segPtr->segNum;
  2665.     pteChange.pageNum = virtAddrPtr->page;
  2666.     pteChange.softPTE = FALSE;
  2667.     pteChange.beforePTE = hardPTE;
  2668.     pteChange.afterPTE = 0;
  2669.     VmStoreTraceRec(VM_TRACE_PTE_CHANGE_REC, sizeof(Vm_TracePTEChange),
  2670.             (Address)&pteChange, TRUE);
  2671.     }
  2672.     /*
  2673.      * Invalidate the page table entry.
  2674.      */
  2675.     for (i = 0; i < VMMACH_CLUSTER_SIZE; i++, addr += VMMACH_PAGE_SIZE_INT) {
  2676.     VmMachWritePTE(pmegNum, addr, (VmMachPTE)0);
  2677.     }
  2678.     pmegPtr = &pmegArray[pmegNum];
  2679.     if (hardPTE & VMMACH_RESIDENT_BIT) {
  2680.     pmegPtr->pageCount--;
  2681.     if (pmegPtr->pageCount == 0) {
  2682.         /*
  2683.          * When the pageCount goes to zero, the pmeg is put onto the end
  2684.          * of the free list so that it can get freed if someone else
  2685.          * needs a pmeg.  It isn't freed here because there is a fair
  2686.          * amount of overhead when freeing a pmeg so its best to keep
  2687.          * it around in case it is needed again.
  2688.          */
  2689.         if (pmegPtr->flags & PMEG_DONT_ALLOC) {
  2690.         List_Insert((List_Links *)pmegPtr, 
  2691.                 LIST_ATREAR(pmegFreeList));
  2692.         } else {
  2693.         List_Move((List_Links *)pmegPtr, 
  2694.               LIST_ATREAR(pmegFreeList));
  2695.         }
  2696.     }
  2697.     }
  2698. }
  2699.  
  2700.  
  2701.  
  2702. /*
  2703.  * ----------------------------------------------------------------------------
  2704.  *
  2705.  * VmMach_PageInvalidate --
  2706.  *
  2707.  *      Invalidate a page for the given segment.  
  2708.  *
  2709.  * Results:
  2710.  *      None.
  2711.  *
  2712.  * Side effects:
  2713.  *      The page table and hardware segment tables associated with the segment
  2714.  *      are modified to invalidate the page.
  2715.  *
  2716.  * ----------------------------------------------------------------------------
  2717.  */
  2718. ENTRY void
  2719. VmMach_PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  2720.     register    Vm_VirtAddr    *virtAddrPtr;
  2721.     unsigned     int        virtPage;
  2722.     Boolean            segDeletion;
  2723. {
  2724.     MASTER_LOCK(vmMachMutexPtr);
  2725.  
  2726.     PageInvalidate(virtAddrPtr, virtPage, segDeletion);
  2727.  
  2728.     MASTER_UNLOCK(vmMachMutexPtr);
  2729. }
  2730.  
  2731.  
  2732. /*
  2733.  *----------------------------------------------------------------------
  2734.  *
  2735.  * VmMach_PinUserPages --
  2736.  *
  2737.  *    Force a user page to be resident in memory.
  2738.  *
  2739.  * Results:
  2740.  *    None.
  2741.  *
  2742.  * Side effects:
  2743.  *    None.
  2744.  *
  2745.  *----------------------------------------------------------------------
  2746.  */
  2747. /*ARGSUSED*/
  2748. void
  2749. VmMach_PinUserPages(mapType, virtAddrPtr, lastPage)
  2750.     int        mapType;
  2751.     Vm_VirtAddr    *virtAddrPtr;
  2752.     int        lastPage;
  2753. {
  2754.     int                *intPtr;
  2755.     int                dummy;
  2756.     register VmMach_SegData    *machPtr;
  2757.     register int        firstSeg;
  2758.     register int        lastSeg;
  2759.  
  2760.     machPtr = virtAddrPtr->segPtr->machPtr;
  2761.  
  2762.     firstSeg = PageToOffSeg(virtAddrPtr->page,virtAddrPtr);
  2763.     lastSeg = PageToOffSeg(lastPage,virtAddrPtr);
  2764.     /*
  2765.      * Lock down the PMEG behind the first segment.
  2766.      */
  2767.     intPtr = (int *) (virtAddrPtr->page << VMMACH_PAGE_SHIFT);
  2768.     while (!PMEGLock(machPtr, firstSeg)) {
  2769.     /*
  2770.      * Touch the page to bring it into memory.  We know that we can
  2771.      * safely touch it because we wouldn't have been called if these
  2772.      * weren't good addresses.
  2773.      */
  2774.     dummy = *intPtr;
  2775.     }
  2776.     /*
  2777.      * Lock down the rest of the segments.
  2778.      */
  2779.     for (firstSeg++; firstSeg <= lastSeg; firstSeg++) {
  2780.     intPtr = (int *)(firstSeg << VMMACH_SEG_SHIFT);
  2781.     while (!PMEGLock(machPtr, firstSeg)) {
  2782.         dummy = *intPtr;
  2783.     }
  2784.     }
  2785. #ifdef lint
  2786.     dummy = dummy;
  2787. #endif
  2788. }
  2789.  
  2790.  
  2791. /*
  2792.  *----------------------------------------------------------------------
  2793.  *
  2794.  * VmMach_UnpinUserPages --
  2795.  *
  2796.  *    Allow a page that was pinned to be unpinned.
  2797.  *
  2798.  * Results:
  2799.  *    None.
  2800.  *
  2801.  * Side effects:
  2802.  *    None.
  2803.  *
  2804.  *----------------------------------------------------------------------
  2805.  */
  2806. ENTRY void
  2807. VmMach_UnpinUserPages(virtAddrPtr, lastPage)
  2808.     Vm_VirtAddr    *virtAddrPtr;
  2809.     int        lastPage;
  2810. {
  2811.     register int    firstSeg;
  2812.     register int    lastSeg;
  2813.     int            pmegNum;
  2814.     register VmMach_SegData    *machPtr;
  2815.  
  2816.     MASTER_LOCK(vmMachMutexPtr);
  2817.  
  2818.     machPtr = virtAddrPtr->segPtr->machPtr;
  2819.     firstSeg = PageToOffSeg(virtAddrPtr->page, virtAddrPtr);
  2820.     lastSeg = PageToOffSeg(lastPage, virtAddrPtr);
  2821.     for (; firstSeg <= lastSeg; firstSeg++) {
  2822.     pmegNum = *GetHardSegPtr(machPtr, firstSeg);
  2823.     if (pmegNum == VMMACH_INV_PMEG) {
  2824.         MASTER_UNLOCK(vmMachMutexPtr);
  2825.         panic("Pinned PMEG invalid???\n");
  2826.         return;
  2827.     }
  2828.     pmegArray[pmegNum].lockCount--;
  2829.     }
  2830.  
  2831.     MASTER_UNLOCK(vmMachMutexPtr);
  2832. }
  2833.  
  2834.  
  2835. /*
  2836.  ----------------------------------------------------------------------
  2837.  *
  2838.  * VmMach_MapInDevice --
  2839.  *
  2840.  *    Map a device at some physical address into kernel virtual address.
  2841.  *    This is for use by the controller initialization routines.
  2842.  *    This routine looks for a free page in the special range of
  2843.  *    kernel virtual that is reserved for this kind of thing and
  2844.  *    sets up the page table so that it references the device.
  2845.  *
  2846.  * Results:
  2847.  *    The kernel virtual address needed to reference the device is returned.
  2848.  *
  2849.  * Side effects:
  2850.  *    The hardware page table is modified.  This may steal another
  2851.  *    page from kernel virtual space, unless a page can be cleverly re-used.
  2852.  *
  2853.  *----------------------------------------------------------------------
  2854.  */
  2855. Address
  2856. VmMach_MapInDevice(devPhysAddr, type)
  2857.     Address    devPhysAddr;    /* Physical address of the device to map in */
  2858.     int        type;        /* Value for the page table entry type field.
  2859.                  * This depends on the address space that
  2860.                  * the devices live in, ie. VME D16 or D32 */
  2861. {
  2862.     Address         virtAddr;
  2863.     Address        freeVirtAddr = (Address)0;
  2864.     Address        freePMEGAddr = (Address)0;
  2865.     int            page;
  2866.     int            pageFrame;
  2867.     VmMachPTE        pte;
  2868.  
  2869.     /*
  2870.      * Get the page frame for the physical device so we can
  2871.      * compare it against existing pte's.
  2872.      */
  2873.     pageFrame = (unsigned)devPhysAddr >> VMMACH_PAGE_SHIFT_INT;
  2874.  
  2875.     /*
  2876.      * Spin through the segments and their pages looking for a free
  2877.      * page or a virtual page that is already mapped to the physical page.
  2878.      */
  2879.     for (virtAddr = (Address)VMMACH_DEV_START_ADDR;
  2880.          virtAddr < (Address)VMMACH_DEV_END_ADDR; ) {
  2881.     if (VmMachGetSegMap(virtAddr) == VMMACH_INV_PMEG) {
  2882.         /* 
  2883.          * If we can't find any free mappings we can use this PMEG.
  2884.          */
  2885.         if (freePMEGAddr == 0) {
  2886.         freePMEGAddr = virtAddr;
  2887.         }
  2888.         virtAddr += VMMACH_SEG_SIZE;
  2889.         continue;
  2890.     }
  2891.     /*
  2892.      * Careful, use the correct page size when incrementing virtAddr.
  2893.      * Use the real hardware size (ignore software klustering) because
  2894.      * we are at a low level munging page table entries ourselves here.
  2895.      */
  2896.     for (page = 0;
  2897.          page < VMMACH_NUM_PAGES_PER_SEG_INT;
  2898.          page++, virtAddr += VMMACH_PAGE_SIZE_INT) {
  2899.         pte = VmMachGetPageMap(virtAddr);
  2900.         if (!(pte & VMMACH_RESIDENT_BIT)) {
  2901.             if (freeVirtAddr == 0) {
  2902.             /*
  2903.              * Note the unused page in this special area of the
  2904.              * kernel virtual address space.
  2905.              */
  2906.             freeVirtAddr = virtAddr;
  2907.         }
  2908.         } else if ((pte & VMMACH_PAGE_FRAME_FIELD) == pageFrame &&
  2909.                VmMachGetPageType(pte) == type) {
  2910.         /*
  2911.          * A page is already mapped for this physical address.
  2912.          */
  2913.         return(virtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  2914.         }
  2915.     }
  2916.     }
  2917.  
  2918.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | pageFrame;
  2919. #ifdef sun3
  2920.     pte |= VMMACH_DONT_CACHE_BIT;
  2921. #endif
  2922.     VmMachSetPageType(pte, type);
  2923.     if (freeVirtAddr != 0) {
  2924.     VmMachSetPageMap(freeVirtAddr, pte);
  2925.     /*
  2926.      * Return the kernel virtual address used to access it.
  2927.      */
  2928.     return(freeVirtAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  2929.     } else if (freePMEGAddr != 0) {
  2930.     int oldContext;
  2931.     int pmeg;
  2932.     int i;
  2933.  
  2934.     /*
  2935.      * Map in a new PMEG so we can use it for mapping.
  2936.      */
  2937.     pmeg = PMEGGet(vm_SysSegPtr, 
  2938.                (int) ((unsigned)freePMEGAddr >> VMMACH_SEG_SHIFT),
  2939.                PMEG_DONT_ALLOC);
  2940.     oldContext = VmMachGetContextReg();
  2941.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  2942.         VmMachSetContextReg(i);
  2943.         VmMachSetSegMap(freePMEGAddr, (unsigned char) pmeg);
  2944.     }
  2945.     VmMachSetContextReg(oldContext);
  2946.     VmMachSetPageMap(freePMEGAddr, pte);
  2947.     return(freePMEGAddr + ((int)devPhysAddr & VMMACH_OFFSET_MASK));
  2948.     } else {
  2949.     return((Address)NIL);
  2950.     }
  2951. }
  2952.  
  2953. /*----------------------------------------------------------------------
  2954.  *
  2955.  * DevBufferInit --
  2956.  *
  2957.  *    Initialize a range of virtual memory to allocate from out of the
  2958.  *    device memory space.
  2959.  *
  2960.  * Results:
  2961.  *    None.
  2962.  *
  2963.  * Side effects:
  2964.  *    The buffer struct is initialized and the hardware page map is zeroed
  2965.  *    out in the range of addresses.
  2966.  *
  2967.  *----------------------------------------------------------------------
  2968.  */
  2969. ENTRY static void
  2970. DevBufferInit()
  2971. {
  2972.     Address        virtAddr;
  2973.     unsigned char    pmeg;
  2974.     int            oldContext;
  2975.     int            i;
  2976.     Address        baseAddr, endAddr;
  2977.  
  2978.     MASTER_LOCK(vmMachMutexPtr);
  2979.  
  2980.     /*
  2981.      * Round base up to next page boundary and end down to page boundary.
  2982.      */
  2983.     baseAddr = (Address)VMMACH_DMA_START_ADDR;
  2984.     endAddr = (Address)(VMMACH_DMA_START_ADDR + VMMACH_DMA_SIZE);
  2985.  
  2986.     /* 
  2987.      * Set up the hardware pages tables in the range of addresses given.
  2988.      */
  2989.     for (virtAddr = baseAddr; virtAddr < endAddr; ) {
  2990.     if (VmMachGetSegMap(virtAddr) != VMMACH_INV_PMEG) {
  2991.         panic("DevBufferInit: DMA space already valid\n");
  2992.     }
  2993.     /* 
  2994.      * Need to allocate a PMEG.
  2995.      */
  2996.     pmeg = PMEGGet(vm_SysSegPtr, 
  2997.                (int) ((unsigned)virtAddr >> VMMACH_SEG_SHIFT),
  2998.                PMEG_DONT_ALLOC);
  2999.     oldContext = VmMachGetContextReg();
  3000.     for (i = 0; i < VMMACH_NUM_CONTEXTS; i++) {
  3001.         VmMachSetContextReg(i);
  3002.         VmMachSetSegMap(virtAddr, pmeg);
  3003.     }
  3004.     VmMachSetContextReg(oldContext);
  3005.     virtAddr += VMMACH_SEG_SIZE;
  3006.     }
  3007.  
  3008.     MASTER_UNLOCK(vmMachMutexPtr);
  3009. }
  3010.  
  3011. /*
  3012.  * 32Bit DMA stubs for the sun3.  The 32-bit user dvma stuff isn't on the
  3013.  * sun3's, just the sun4's.
  3014.  */
  3015. /*ARGSUSED*/
  3016. Address
  3017. VmMach_32BitDMAAlloc(numBytes, srcAddr)
  3018.     int        numBytes;        /* Number of bytes to map in. */
  3019.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  3020. {
  3021.     panic("VmMach_32BitDMAAlloc: should never be called on a sun3!\n");
  3022.     return (Address) 0;
  3023. }
  3024. /*ARGSUSED*/
  3025. void
  3026. VmMach_32BitDMAFree(numBytes, mapAddr)
  3027.     int        numBytes;        /* Number of bytes to map in. */
  3028.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  3029. {
  3030.     panic("VmMach_32BitDMAFree: should never be called on a sun3!\n");
  3031. }
  3032.  
  3033. static    Boolean    dmaPageBitMap[VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT];
  3034.  
  3035. static Boolean dmaInitialized = FALSE;
  3036.  
  3037. /*
  3038.  ----------------------------------------------------------------------
  3039.  *
  3040.  * VmMach_DMAAlloc --
  3041.  *
  3042.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  3043.  *    
  3044.  * Results:
  3045.  *    Pointer into kernel virtual address space of where to access the
  3046.  *    memory, or NIL if the request couldn't be satisfied.
  3047.  *
  3048.  * Side effects:
  3049.  *    The hardware page table is modified.
  3050.  *
  3051.  *----------------------------------------------------------------------
  3052.  */
  3053. Address
  3054. VmMach_DMAAlloc(numBytes, srcAddr)
  3055.     int        numBytes;        /* Number of bytes to map in. */
  3056.     Address    srcAddr;    /* Kernel virtual address to start mapping in.*/
  3057. {
  3058.     Address    beginAddr;
  3059.     Address    endAddr;
  3060.     int        numPages;
  3061.     int        i, j;
  3062.     VmMachPTE    pte;
  3063.     Boolean    foundIt = FALSE;
  3064.     int        virtPage;
  3065.  
  3066.     if (!dmaInitialized) {
  3067.     dmaInitialized = TRUE;
  3068.     DevBufferInit();
  3069.     }
  3070.     /* calculate number of pages needed */
  3071.                         /* beginning of first page */
  3072.     beginAddr = (Address) (((unsigned int)(srcAddr)) & ~VMMACH_OFFSET_MASK_INT);
  3073.                         /* begging of last page */
  3074.     endAddr = (Address) ((((unsigned int) srcAddr) + numBytes) &
  3075.         ~VMMACH_OFFSET_MASK_INT);
  3076.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3077.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  3078.  
  3079.     /* see if request can be satisfied */
  3080.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  3081.     if (dmaPageBitMap[i] == 1) {
  3082.         continue;
  3083.     }
  3084.     for (j = 1; j < numPages; j++) {
  3085.         if (dmaPageBitMap[i + j] == 1) {
  3086.         break;
  3087.         }
  3088.     }
  3089.     if (j == numPages) {
  3090.         foundIt = TRUE;
  3091.         break;
  3092.     }
  3093.     }
  3094.     if (!foundIt) {
  3095.     return (Address) NIL;
  3096.     }
  3097.     for (j = 0; j < numPages; j++) {
  3098.     dmaPageBitMap[i + j] = 1;    /* allocate page */
  3099.     virtPage = ((unsigned int) srcAddr) >> VMMACH_PAGE_SHIFT;
  3100.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  3101.           VirtToPhysPage(Vm_GetKernPageFrame(virtPage));
  3102.     SET_ALL_PAGE_MAP(((i + j) * VMMACH_PAGE_SIZE_INT) +
  3103.         VMMACH_DMA_START_ADDR, pte);
  3104.     srcAddr += VMMACH_PAGE_SIZE;
  3105.     }
  3106.     beginAddr = (Address) (VMMACH_DMA_START_ADDR + (i * VMMACH_PAGE_SIZE_INT) +
  3107.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  3108.     return beginAddr;
  3109. }
  3110.  
  3111. /*
  3112.  ----------------------------------------------------------------------
  3113.  *
  3114.  * VmMach_DMAAllocContiguous --
  3115.  *
  3116.  *    Allocate a set of virtual pages to a routine for mapping purposes.
  3117.  *    
  3118.  * Results:
  3119.  *    Pointer into kernel virtual address space of where to access the
  3120.  *    memory, or NIL if the request couldn't be satisfied.
  3121.  *
  3122.  * Side effects:
  3123.  *    The hardware page table is modified.
  3124.  *
  3125.  *----------------------------------------------------------------------
  3126.  */
  3127. ReturnStatus
  3128. VmMach_DMAAllocContiguous(inScatGathPtr, scatGathLength, outScatGathPtr)
  3129.     register Net_ScatterGather    *inScatGathPtr;
  3130.     register int        scatGathLength;
  3131.     register Net_ScatterGather    *outScatGathPtr;
  3132. {
  3133.     Address    beginAddr;
  3134.     Address    endAddr;
  3135.     int        numPages;
  3136.     int        i, j;
  3137.     VmMachPTE    pte;
  3138.     Boolean    foundIt = FALSE;
  3139.     int        virtPage;
  3140.     Net_ScatterGather        *inPtr;
  3141.     Net_ScatterGather        *outPtr;
  3142.     int                pageOffset;
  3143.     Address            srcAddr;
  3144.  
  3145.     if (!dmaInitialized) {
  3146.     dmaInitialized = TRUE;
  3147.     DevBufferInit();
  3148.     }
  3149.     /* calculate number of pages needed */
  3150.     inPtr = inScatGathPtr;
  3151.     outPtr = outScatGathPtr;
  3152.     numPages = 0;
  3153.     for (i = 0; i < scatGathLength; i++) {
  3154.     if (inPtr->length > 0) {
  3155.         /* beginning of first page */
  3156.         beginAddr = (Address) (((unsigned int)(inPtr->bufAddr)) & 
  3157.             ~VMMACH_OFFSET_MASK_INT);
  3158.         /* beginning of last page */
  3159.         endAddr = (Address) ((((unsigned int) inPtr->bufAddr) + 
  3160.         inPtr->length - 1) & ~VMMACH_OFFSET_MASK_INT);
  3161.         /* 
  3162.          * Temporarily store the number of pages in the out scatter/gather
  3163.          * array.
  3164.          */
  3165.         outPtr->length =
  3166.             (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3167.             (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  3168.     } else {
  3169.         outPtr->length = 0;
  3170.     }
  3171.     if ((i == 0) && (outPtr->length != 1)) {
  3172.         panic("Help! Help! I'm being repressed!\n");
  3173.     }
  3174.     numPages += outPtr->length;
  3175.     inPtr++;
  3176.     outPtr++;
  3177.     }
  3178.  
  3179.     /* see if request can be satisfied */
  3180.     for (i = 0; i < (VMMACH_DMA_SIZE / VMMACH_PAGE_SIZE_INT); i++) {
  3181.     if (dmaPageBitMap[i] == 1) {
  3182.         continue;
  3183.     }
  3184.     for (j = 1; j < numPages; j++) {
  3185.         if (dmaPageBitMap[i + j] == 1) {
  3186.         break;
  3187.         }
  3188.     }
  3189.     if (j == numPages) {
  3190.         foundIt = TRUE;
  3191.         break;
  3192.     }
  3193.     }
  3194.     if (!foundIt) {
  3195.     return FAILURE;
  3196.     }
  3197.     pageOffset = i;
  3198.     inPtr = inScatGathPtr;
  3199.     outPtr = outScatGathPtr;
  3200.     for (i = 0; i < scatGathLength; i++) {
  3201.     srcAddr = inPtr->bufAddr;
  3202.     numPages = outPtr->length;
  3203.     for (j = 0; j < numPages; j++) {
  3204.         dmaPageBitMap[pageOffset + j] = 1;    /* allocate page */
  3205.         virtPage = ((unsigned int) srcAddr) >> VMMACH_PAGE_SHIFT;
  3206.         pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT |
  3207.           VirtToPhysPage(Vm_GetKernPageFrame(virtPage));
  3208.         SET_ALL_PAGE_MAP(((pageOffset + j) * VMMACH_PAGE_SIZE_INT) +
  3209.             VMMACH_DMA_START_ADDR, pte);
  3210.         srcAddr += VMMACH_PAGE_SIZE;
  3211.     }
  3212.     outPtr->bufAddr = (Address) (VMMACH_DMA_START_ADDR + 
  3213.         (pageOffset * VMMACH_PAGE_SIZE_INT) + 
  3214.         (((unsigned int) srcAddr) & VMMACH_OFFSET_MASK));
  3215.     pageOffset += numPages;
  3216.     outPtr->length = inPtr->length;
  3217.     inPtr++;
  3218.     outPtr++;
  3219.     }
  3220.     return SUCCESS;
  3221. }
  3222.  
  3223.  
  3224. /*
  3225.  ----------------------------------------------------------------------
  3226.  *
  3227.  * VmMach_DMAFree --
  3228.  *
  3229.  *    Free a previously allocated set of virtual pages for a routine that
  3230.  *    used them for mapping purposes.
  3231.  *    
  3232.  * Results:
  3233.  *    None.
  3234.  *
  3235.  * Side effects:
  3236.  *    The hardware page table is modified.
  3237.  *
  3238.  *----------------------------------------------------------------------
  3239.  */
  3240. void
  3241. VmMach_DMAFree(numBytes, mapAddr)
  3242.     int        numBytes;        /* Number of bytes to map in. */
  3243.     Address    mapAddr;    /* Kernel virtual address to unmap.*/
  3244. {
  3245.     Address    beginAddr;
  3246.     Address    endAddr;
  3247.     int        numPages;
  3248.     int        i, j;
  3249.  
  3250.     /* calculate number of pages to free */
  3251.                         /* beginning of first page */
  3252.     beginAddr = (Address) (((unsigned int) mapAddr) & ~VMMACH_OFFSET_MASK_INT);
  3253.                         /* beginning of last page */
  3254.     endAddr = (Address) ((((unsigned int) mapAddr) + numBytes) &
  3255.         ~VMMACH_OFFSET_MASK_INT);
  3256.     numPages = (((unsigned int) endAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3257.         (((unsigned int) beginAddr) >> VMMACH_PAGE_SHIFT_INT) + 1;
  3258.  
  3259.     i = (((unsigned int) mapAddr) >> VMMACH_PAGE_SHIFT_INT) -
  3260.     (VMMACH_DMA_START_ADDR >> VMMACH_PAGE_SHIFT_INT);
  3261.     for (j = 0; j < numPages; j++) {
  3262.     dmaPageBitMap[i + j] = 0;    /* free page */
  3263.     SET_ALL_PAGE_MAP(mapAddr, (VmMachPTE) 0);
  3264.     mapAddr = (Address)(((unsigned int) mapAddr) + VMMACH_PAGE_SIZE_INT);
  3265.     }
  3266.     return;
  3267. }
  3268.  
  3269.  
  3270. #if 0 /* Dead code shirriff 9/90 */
  3271. /*
  3272.  * ----------------------------------------------------------------------------
  3273.  *
  3274.  * VmMach_GetDevicePage --
  3275.  *
  3276.  *      Allocate and validate a page at the given virtual address.  It is
  3277.  *    assumed that this page does not fall into the range of virtual 
  3278.  *    addresses used to allocate kernel code and data and that there is
  3279.  *    already a PMEG allocate for it.
  3280.  *
  3281.  * Results:
  3282.  *      None.
  3283.  *
  3284.  * Side effects:
  3285.  *      The hardware segment table for the kernel is modified to validate the
  3286.  *    the page.
  3287.  *
  3288.  * ----------------------------------------------------------------------------
  3289.  */
  3290. void
  3291. VmMach_GetDevicePage(virtAddr) 
  3292.     Address    virtAddr; /* Virtual address where a page has to be 
  3293.                * validated at. */
  3294. {
  3295.     VmMachPTE    pte;
  3296.     int        page;
  3297.  
  3298.     page = Vm_KernPageAllocate();
  3299.     if (page == -1) {
  3300.     panic("Vm_GetDevicePage: Couldn't get memory\n");
  3301.     }
  3302.     pte = VMMACH_RESIDENT_BIT | VMMACH_KRW_PROT | VirtToPhysPage(page);
  3303.     SET_ALL_PAGE_MAP(virtAddr, pte);
  3304. }
  3305.  
  3306. #endif
  3307.  
  3308. /*
  3309.  * ----------------------------------------------------------------------------
  3310.  *
  3311.  * VmMach_MapKernelIntoUser --
  3312.  *
  3313.  *      Map a portion of kernel memory into the user's heap segment.  
  3314.  *    It will only map objects on hardware segment boundaries.  This is 
  3315.  *    intended to be used to map devices such as video memory.
  3316.  *
  3317.  *    NOTE: It is assumed that the user process knows what the hell it is
  3318.  *          doing.
  3319.  *
  3320.  * Results:
  3321.  *      Return the virtual address that it chose to map the memory at.
  3322.  *
  3323.  * Side effects:
  3324.  *      The hardware segment table for the user process's segment is modified
  3325.  *    to map in the addresses.
  3326.  *
  3327.  * ----------------------------------------------------------------------------
  3328.  */
  3329. ReturnStatus
  3330. VmMach_MapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr,
  3331.              realVirtAddrPtr) 
  3332.     unsigned    int    kernelVirtAddr;    /* Kernel virtual address to map in. */
  3333.     int    numBytes;            /* Number of bytes to map. */
  3334.     unsigned int userVirtAddr;    /* User virtual address to attempt to start 
  3335.                    mapping in at. */
  3336.     unsigned int *realVirtAddrPtr;/* Where we were able to start mapping at. */
  3337. {
  3338.     Address             newUserVirtAddr;
  3339.     ReturnStatus        status;
  3340.  
  3341.     status = VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes,
  3342.             userVirtAddr, &newUserVirtAddr);
  3343.  
  3344.     if (status != SUCCESS) {
  3345.         return status;
  3346.     }
  3347.  
  3348.     return Vm_CopyOut(4, (Address) &newUserVirtAddr, (Address) realVirtAddrPtr);
  3349. }
  3350.  
  3351.  
  3352. /*
  3353.  * ----------------------------------------------------------------------------
  3354.  *
  3355.  * Vm_IntMapKernelIntoUser --
  3356.  *
  3357.  *      Map a portion of kernel memory into the user's heap segment.
  3358.  *      It will only map objects on hardware segment boundaries.  This is
  3359.  *      intended to be used to map devices such as video memory.
  3360.  *
  3361.  *      This routine can be called from within the kernel since it doesn't
  3362.  *      do a Vm_CopyOut of the new user virtual address.
  3363.  *
  3364.  *      NOTE: It is assumed that the user process knows what the hell it is
  3365.  *            doing.
  3366.  *
  3367.  * Results:
  3368.  *      SUCCESS or FAILURE status.
  3369.  *      Return the virtual address that it chose to map the memory at in
  3370.  *      an out parameter.
  3371.  *
  3372.  * Side effects:
  3373.  *      The hardware segment table for the user process's segment is modified
  3374.  *      to map in the addresses.
  3375.  *
  3376.  * ----------------------------------------------------------------------------
  3377.  */
  3378. ReturnStatus
  3379. VmMach_IntMapKernelIntoUser(kernelVirtAddr, numBytes, userVirtAddr, newAddrPtr)
  3380.     unsigned int        kernelVirtAddr;         /* Kernel virtual address
  3381.                                                  * to map in. */
  3382.     int numBytes;                               /* Number of bytes to map. */
  3383.     unsigned int        userVirtAddr;           /* User virtual address to
  3384.                                                  * attempt to start mapping
  3385.                                                  * in at. */
  3386.     Address             *newAddrPtr;            /* New user address. */
  3387. {
  3388.     int                numSegs;
  3389.     int                firstPage;
  3390.     int                numPages;
  3391.     Proc_ControlBlock        *procPtr;
  3392.     register    Vm_Segment    *segPtr;
  3393.     int                hardSegNum;
  3394.     int                i;
  3395.     unsigned int        pte;
  3396.  
  3397.     procPtr = Proc_GetCurrentProc();
  3398.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  3399.  
  3400.     numSegs = numBytes >> VMMACH_SEG_SHIFT;
  3401.     numPages = numSegs * VMMACH_SEG_SIZE / VMMACH_PAGE_SIZE;
  3402.  
  3403.     /*
  3404.      * Make user virtual address hardware segment aligned (round up) and 
  3405.      * make sure that there is enough space to map things.
  3406.      */
  3407.     hardSegNum = 
  3408.         (unsigned int) (userVirtAddr + VMMACH_SEG_SIZE - 1) >> VMMACH_SEG_SHIFT;
  3409.     userVirtAddr = hardSegNum << VMMACH_SEG_SHIFT;
  3410.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  3411.     return(SYS_INVALID_ARG);
  3412.     }
  3413.  
  3414.     /*
  3415.      * Make sure will fit into the kernel's VAS.  Assume that is hardware
  3416.      * segment aligned.
  3417.      */
  3418.     hardSegNum = (unsigned int) (kernelVirtAddr) >> VMMACH_SEG_SHIFT;
  3419.     if (hardSegNum + numSegs > VMMACH_NUM_SEGS_PER_CONTEXT) {
  3420.     return(SYS_INVALID_ARG);
  3421.     }
  3422.  
  3423.     /*
  3424.      * Invalidate all virtual memory for the heap segment of this process
  3425.      * in the given range of virtual addresses that we are to map.  This
  3426.      * assures us that there aren't any hardware pages allocated for this
  3427.      * segment in this range of addresses.
  3428.      */
  3429.     firstPage = (unsigned int) (userVirtAddr) >> VMMACH_PAGE_SHIFT;
  3430.     (void)Vm_DeleteFromSeg(segPtr, firstPage, firstPage + numPages - 1);
  3431.  
  3432.     /*
  3433.      * Now go into the kernel's hardware segment table and copy the
  3434.      * segment table entries into the heap segments hardware segment table.
  3435.      */
  3436.     bcopy((Address)GetHardSegPtr(vm_SysSegPtr->machPtr, hardSegNum),
  3437.     (Address)GetHardSegPtr(segPtr->machPtr,
  3438.         (unsigned int)userVirtAddr >> VMMACH_SEG_SHIFT), numSegs);
  3439.     for (i = 0; i < numSegs * VMMACH_NUM_PAGES_PER_SEG_INT; i++) {
  3440.     pte = VmMachGetPageMap((Address)(kernelVirtAddr +
  3441.         (i * VMMACH_PAGE_SIZE_INT)));
  3442.     pte &= ~VMMACH_KR_PROT;
  3443.     pte |= VMMACH_URW_PROT;
  3444.     VmMachSetPageMap((Address)(kernelVirtAddr + (i*VMMACH_PAGE_SIZE_INT)),
  3445.         pte);
  3446.     }
  3447.  
  3448.     /*
  3449.      * Make sure this process never migrates.
  3450.      */
  3451.     Proc_NeverMigrate(procPtr);
  3452.     
  3453.     /* 
  3454.      * Reinitialize this process's context using the new segment table.
  3455.      */
  3456.     VmMach_ReinitContext(procPtr);
  3457.     *newAddrPtr = (Address)userVirtAddr;
  3458.  
  3459.     return SUCCESS;
  3460. }
  3461.  
  3462.  
  3463. /*
  3464.  * ----------------------------------------------------------------------------
  3465.  *
  3466.  * VmMach_Trace --
  3467.  *
  3468.  *      Scan through all of the PMEGs generating trace records for those pages
  3469.  *    that have been referenced or modified since the last time that we
  3470.  *    checked.
  3471.  *  
  3472.  * Results:
  3473.  *      None.
  3474.  *
  3475.  * Side effects:
  3476.  *    None.
  3477.  *
  3478.  * ----------------------------------------------------------------------------
  3479.  */
  3480. ENTRY void
  3481. VmMach_Trace()
  3482. {
  3483.     register    PMEG            *pmegPtr;
  3484.     register    Vm_Segment        *segPtr;
  3485.     register    int            pmegNum;
  3486.     register    int            curTraceTime;
  3487.  
  3488.     MASTER_LOCK(vmMachMutexPtr);
  3489.  
  3490.     /*
  3491.      * Save the current trace time and then increment it to ensure that
  3492.      * any segments that get used while we are scanning memory won't get 
  3493.      * missed.
  3494.      */
  3495.     curTraceTime = vmTraceTime;
  3496.     vmTraceTime++;
  3497.  
  3498.     /*
  3499.      * Spin through all of the pmegs.
  3500.      */
  3501.     for (pmegNum = 0, pmegPtr = pmegArray;
  3502.      pmegNum < VMMACH_NUM_PMEGS;
  3503.      pmegPtr++, pmegNum++) {
  3504.     segPtr = pmegPtr->segPtr;
  3505.     if ((pmegPtr->flags & PMEG_NEVER_FREE) ||
  3506.         segPtr == (Vm_Segment *)NIL ||
  3507.         segPtr->traceTime < curTraceTime) {
  3508.         continue;
  3509.     }
  3510.     vmTraceStats.machStats.pmegsChecked++;
  3511.     printedSegTrace = FALSE;
  3512.     tracePMEGPtr = pmegPtr;
  3513.     VmMachTracePMEG(pmegNum);
  3514.     }
  3515.  
  3516.     MASTER_UNLOCK(vmMachMutexPtr);
  3517.  
  3518.     VmCheckTraceOverflow();
  3519. }
  3520.  
  3521.  
  3522. /*
  3523.  * ----------------------------------------------------------------------------
  3524.  *
  3525.  * VmMachTracePage --
  3526.  *
  3527.  *      Generate a trace record for the given page.
  3528.  *  
  3529.  * Results:
  3530.  *      None.
  3531.  *
  3532.  * Side effects:
  3533.  *    None.
  3534.  *
  3535.  * ----------------------------------------------------------------------------
  3536.  */
  3537. INTERNAL void
  3538. VmMachTracePage(pte, pageNum)
  3539.     register    VmMachPTE    pte;    /* Page table entry to be traced. */
  3540.     unsigned    int        pageNum;/* Inverse of page within PMEG. */
  3541. {
  3542.     Vm_TraceSeg            segTrace;
  3543.     Vm_TracePage        pageTrace;
  3544.     register    PMEG        *pmegPtr;
  3545.     register    Vm_Segment    *segPtr;
  3546.  
  3547.     refModMap[PhysToVirtPage(pte & VMMACH_PAGE_FRAME_FIELD)] |=
  3548.             pte & (VMMACH_REFERENCED_BIT | VMMACH_MODIFIED_BIT);
  3549.     if (!printedSegTrace) {
  3550.     /*
  3551.      * Trace of the segment.
  3552.      */
  3553.     printedSegTrace = TRUE;
  3554.     pmegPtr = tracePMEGPtr;
  3555.     segPtr = pmegPtr->segPtr;
  3556.     segTrace.hardSegNum = pmegPtr->hardSegNum;
  3557.     segTrace.softSegNum = segPtr->segNum;
  3558.     segTrace.segType = segPtr->type;
  3559.     segTrace.refCount = segPtr->refCount;
  3560.     VmStoreTraceRec(VM_TRACE_SEG_REC, sizeof(Vm_TraceSeg), 
  3561.             (Address)&segTrace, FALSE);
  3562.     }
  3563.  
  3564.     /*
  3565.      * Trace the page.
  3566.      */
  3567.     pageTrace = VMMACH_NUM_PAGES_PER_SEG_INT - pageNum;
  3568.     if (pte & VMMACH_REFERENCED_BIT) {
  3569.     pageTrace |= VM_TRACE_REFERENCED;
  3570.     } 
  3571.     if (pte & VMMACH_MODIFIED_BIT) {
  3572.     pageTrace |= VM_TRACE_MODIFIED;
  3573.     }
  3574.     VmStoreTraceRec(0, sizeof(Vm_TracePage), (Address)&pageTrace, FALSE);
  3575. }
  3576.  
  3577.  
  3578. /*
  3579.  *----------------------------------------------------------------------
  3580.  *
  3581.  * VmMach_FlushPage --
  3582.  *
  3583.  *    Flush the page at the given virtual address from all caches.  We
  3584.  *    don't have to do anything on the Sun-2 and Sun-3 workstations
  3585.  *    that we have.
  3586.  *
  3587.  * Results:
  3588.  *    None.
  3589.  *
  3590.  * Side effects:
  3591.  *    The given page is flushed from the caches.
  3592.  *
  3593.  *----------------------------------------------------------------------
  3594.  */
  3595. /*ARGSUSED*/
  3596. void
  3597. VmMach_FlushPage(virtAddrPtr, invalidate)
  3598.     Vm_VirtAddr    *virtAddrPtr;
  3599.     Boolean    invalidate;    /* Should invalidate the pte after flushing. */
  3600. {
  3601. }
  3602.  
  3603.  
  3604. /*
  3605.  *----------------------------------------------------------------------
  3606.  *
  3607.  * VmMach_HandleSegMigration --
  3608.  *
  3609.  *    Handle machine-dependent aspects of segment preparation for
  3610.  *    migration.  There's nothing to do on this machine.
  3611.  *
  3612.  * Results:
  3613.  *    None.
  3614.  *
  3615.  * Side effects:
  3616.  *    None.
  3617.  *
  3618.  *----------------------------------------------------------------------
  3619.  */
  3620. /*ARGSUSED*/
  3621. void
  3622. VmMach_HandleSegMigration(segPtr)
  3623.     Vm_Segment    *segPtr;
  3624. {
  3625.     return;
  3626. }
  3627.  
  3628.  
  3629. /*
  3630.  *----------------------------------------------------------------------
  3631.  *
  3632.  * VmMach_SetProtForDbg --
  3633.  *
  3634.  *    Set the protection of the kernel pages for the debugger.
  3635.  *
  3636.  * Results:
  3637.  *    None.
  3638.  *
  3639.  * Side effects:
  3640.  *    The protection is set for the given range of kernel addresses.
  3641.  *
  3642.  *----------------------------------------------------------------------
  3643.  */
  3644. void
  3645. VmMach_SetProtForDbg(readWrite, numBytes, addr)
  3646.     Boolean    readWrite;    /* TRUE if should make pages writable, FALSE
  3647.                  * if should make read-only. */
  3648.     int        numBytes;    /* Number of bytes to change protection for. */
  3649.     Address    addr;        /* Address to start changing protection at. */
  3650. {
  3651.     register    Address        virtAddr;
  3652.     register    VmMachPTE     pte;
  3653.     register    int        firstPage;
  3654.     register    int        lastPage;
  3655.  
  3656.     firstPage = (unsigned)addr >> VMMACH_PAGE_SHIFT;
  3657.     lastPage = ((unsigned)addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  3658.     for (; firstPage <= lastPage; firstPage++) {
  3659.     virtAddr = (Address) (firstPage << VMMACH_PAGE_SHIFT);
  3660.     pte = VmMachGetPageMap(virtAddr);
  3661.     pte &= ~VMMACH_PROTECTION_FIELD;
  3662.     pte |= readWrite ? VMMACH_KRW_PROT : VMMACH_KR_PROT;
  3663.     SET_ALL_PAGE_MAP(virtAddr, pte);
  3664.     }
  3665. }
  3666.  
  3667.  
  3668. /*
  3669.  *----------------------------------------------------------------------
  3670.  *
  3671.  * VmMach_Cmd --
  3672.  *
  3673.  *    Machine dependent vm commands.
  3674.  *
  3675.  * Results:
  3676.  *    None.
  3677.  *
  3678.  * Side effects:
  3679.  *    None.
  3680.  *
  3681.  *----------------------------------------------------------------------
  3682.  */
  3683. /*ARGSUSED*/
  3684. ReturnStatus
  3685. VmMach_Cmd(command, arg)
  3686.     int    command;
  3687.     int arg;
  3688. {
  3689.     return(GEN_INVALID_ARG);
  3690. }
  3691.  
  3692.  
  3693. /*
  3694.  *----------------------------------------------------------------------
  3695.  *
  3696.  * VmMach_FlushCode --
  3697.  *
  3698.  *    Machine dependent vm commands.
  3699.  *
  3700.  * Results:
  3701.  *    None.
  3702.  *
  3703.  * Side effects:
  3704.  *    None.
  3705.  *
  3706.  *----------------------------------------------------------------------
  3707.  */
  3708. /*ARGSUSED*/
  3709. void
  3710. VmMach_FlushCode(procPtr, virtAddrPtr, virtPage, numBytes)
  3711.     Proc_ControlBlock    *procPtr;
  3712.     Vm_VirtAddr        *virtAddrPtr;
  3713.     unsigned        virtPage;
  3714.     int            numBytes;
  3715. {
  3716. }
  3717.  
  3718. /*
  3719.  * Dummy function which will turn out to be the function that the debugger
  3720.  * prints out on a backtrace after a trap.  The debugger gets confused
  3721.  * because trap stacks originate from assembly language stacks.  I decided
  3722.  * to make a dummy procedure because it was to confusing seeing the
  3723.  * previous procedure (VmMach_MapKernelIntoUser) on every backtrace.
  3724.  */
  3725. void
  3726. VmMachTrap()
  3727. {
  3728. }
  3729.  
  3730. /*
  3731.  *----------------------------------------------------------------------
  3732.  *
  3733.  * ByteFill --
  3734.  *
  3735.  *    Fill numBytes at the given address.  This routine is optimized to do 
  3736.  *      4-byte fills.  However, if the address is odd then it is forced to
  3737.  *      do single byte fills.
  3738.  *
  3739.  * Results:
  3740.  *    numBytes bytes of the fill byte are placed at *destPtr at the 
  3741.  *    given address.
  3742.  *
  3743.  * Side effects:
  3744.  *    None.
  3745.  *
  3746.  *----------------------------------------------------------------------
  3747.  */
  3748.  
  3749. static void
  3750. ByteFill(fillByte, numBytes, destPtr)
  3751.     register unsigned int fillByte;    /* The byte to be filled in. */
  3752.     register int numBytes;    /* The number of bytes to be filled in. */
  3753.     Address destPtr;        /* Where to fill. */
  3754. {
  3755.     register unsigned int fillInt = 
  3756.     (fillByte) | (fillByte << 8) | (fillByte << 16) | (fillByte << 24);
  3757.  
  3758.     register int *dPtr = (int *) destPtr;
  3759.     
  3760.     /*
  3761.      * If the address is on an aligned boundary then fill in as much
  3762.      * as we can in big transfers (and also avoid loop overhead by
  3763.      * storing many fill ints per iteration).  Once we have less than
  3764.      * 4 bytes to fill then it must be done by byte copies.
  3765.      */
  3766. #define WORDMASK    0x1
  3767.  
  3768.     if (((int) dPtr & WORDMASK) == 0) {
  3769.     while (numBytes >= 32) {
  3770.         *dPtr++ = fillInt;
  3771.         *dPtr++ = fillInt;
  3772.         *dPtr++ = fillInt;
  3773.         *dPtr++ = fillInt;
  3774.         *dPtr++ = fillInt;
  3775.         *dPtr++ = fillInt;
  3776.         *dPtr++ = fillInt;
  3777.         *dPtr++ = fillInt;
  3778.         numBytes -= 32;
  3779.     }
  3780.     while (numBytes >= 4) {
  3781.         *dPtr++ = fillInt;
  3782.         numBytes -= 4;
  3783.     }
  3784.     destPtr = (char *) dPtr;
  3785.     }
  3786.  
  3787.     /*
  3788.      * Fill in the remaining bytes
  3789.      */
  3790.  
  3791.     while (numBytes > 0) {
  3792.     *destPtr++ = fillByte;
  3793.     numBytes--;
  3794.     }
  3795. }
  3796.  
  3797.  
  3798. #define ALLOC(x,s)    (sharedData->allocVector[(x)]=s)
  3799. #define FREE(x)        (sharedData->allocVector[(x)]=0)
  3800. #define SIZE(x)        (sharedData->allocVector[(x)])
  3801. #define ISFREE(x)    (sharedData->allocVector[(x)]==0)
  3802.  
  3803.  
  3804.  
  3805. /*
  3806.  * ----------------------------------------------------------------------------
  3807.  *
  3808.  * VmMach_Alloc --
  3809.  *
  3810.  *      Allocates a region of shared memory;
  3811.  *
  3812.  * Results:
  3813.  *      SUCCESS if the region can be allocated.
  3814.  *    The starting address is returned in addr.
  3815.  *
  3816.  * Side effects:
  3817.  *      The allocation vector is updated.
  3818.  *
  3819.  * ----------------------------------------------------------------------------
  3820.  */
  3821. static ReturnStatus
  3822. VmMach_Alloc(sharedData, regionSize, addr)
  3823.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info.  */
  3824.     int            regionSize;    /* Size of region to allocate. */
  3825.     Address        *addr;        /* Address of region. */
  3826. {
  3827.     int numBlocks = (regionSize+VMMACH_SHARED_BLOCK_SIZE-1) /
  3828.         VMMACH_SHARED_BLOCK_SIZE;
  3829.     int i, blockCount, firstBlock;
  3830.  
  3831.     if (sharedData->allocVector == (int *)NULL || sharedData->allocVector ==
  3832.         (int *)NIL) {
  3833.     dprintf("VmMach_Alloc: allocVector uninitialized!\n");
  3834.     }
  3835.  
  3836.     /*
  3837.      * Loop through the alloc vector until we find numBlocks free blocks
  3838.      * consecutively.
  3839.      */
  3840.     blockCount = 0;
  3841.     for (i=sharedData->allocFirstFree;
  3842.         i<=VMMACH_SHARED_NUM_BLOCKS-1 && blockCount<numBlocks;i++) {
  3843.     if (ISFREE(i)) {
  3844.         blockCount++;
  3845.     } else {
  3846.         blockCount = 0;
  3847.         if (i==sharedData->allocFirstFree) {
  3848.         sharedData->allocFirstFree++;
  3849.         }
  3850.     }
  3851.     }
  3852.     if (blockCount < numBlocks) {
  3853.     if (debugVmStubs) {
  3854.         dprintf("VmMach_Alloc: got %d blocks of %d of %d total\n",
  3855.             blockCount,numBlocks,VMMACH_SHARED_NUM_BLOCKS);
  3856.     }
  3857.     return VM_NO_SEGMENTS;
  3858.     }
  3859.     firstBlock = i-blockCount;
  3860.     if (firstBlock == sharedData->allocFirstFree) {
  3861.     sharedData->allocFirstFree += blockCount;
  3862.     }
  3863.     *addr = (Address)(firstBlock*VMMACH_SHARED_BLOCK_SIZE +
  3864.         VMMACH_SHARED_START_ADDR);
  3865.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  3866.     ALLOC(i,numBlocks);
  3867.     }
  3868.     dprintf("VmMach_Alloc: got %d blocks at %d (%x)\n",
  3869.         numBlocks,firstBlock,*addr);
  3870.     return SUCCESS;
  3871. }
  3872.  
  3873.  
  3874. /*
  3875.  * ----------------------------------------------------------------------------
  3876.  *
  3877.  * VmMach_Unalloc --
  3878.  *
  3879.  *      Frees a region of shared address space.
  3880.  *
  3881.  * Results:
  3882.  *      None.
  3883.  *
  3884.  * Side effects:
  3885.  *      The allocation vector is updated.
  3886.  *
  3887.  * ----------------------------------------------------------------------------
  3888.  */
  3889.  
  3890. static void
  3891. VmMach_Unalloc(sharedData, addr)
  3892.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info. */
  3893.     Address    addr;        /* Address of region. */
  3894. {
  3895.     int firstBlock = ((int)addr-VMMACH_SHARED_START_ADDR) /
  3896.         VMMACH_SHARED_BLOCK_SIZE;
  3897.     int numBlocks = SIZE(firstBlock);
  3898.     int i;
  3899.  
  3900.     dprintf("VmMach_Unalloc: freeing %d blocks at %x\n",numBlocks,addr);
  3901.     if (firstBlock < sharedData->allocFirstFree) {
  3902.     sharedData->allocFirstFree = firstBlock;
  3903.     }
  3904.     for (i=0;i<numBlocks;i++) {
  3905.     if (ISFREE(i+firstBlock)) {
  3906.         if (debugVmStubs) {
  3907.         printf("Freeing free shared address %d %d %x\n",i,i+firstBlock,
  3908.             (int)addr);
  3909.         }
  3910.         return;
  3911.     }
  3912.     FREE(i+firstBlock);
  3913.     }
  3914. }
  3915.  
  3916. /*
  3917.  * ----------------------------------------------------------------------------
  3918.  *
  3919.  * VmMach_SharedStartAddr --
  3920.  *
  3921.  *      Determine the starting address for a shared segment.
  3922.  *
  3923.  * Results:
  3924.  *      Returns the proper start address for the segment.
  3925.  *
  3926.  * Side effects:
  3927.  *      Allocates part of the shared address space.
  3928.  *
  3929.  * ----------------------------------------------------------------------------
  3930.  */
  3931. ReturnStatus
  3932. VmMach_SharedStartAddr(procPtr,size,reqAddr, fixed)
  3933.     Proc_ControlBlock   *procPtr;
  3934.     int             size;           /* Length of shared segment. */
  3935.     Address         *reqAddr;        /* Requested start address. */
  3936.     int             fixed;          /* 1 if fixed address requested. */
  3937. {
  3938.     int numBlocks = (size+VMMACH_SHARED_BLOCK_SIZE-1) /
  3939.             VMMACH_SHARED_BLOCK_SIZE;
  3940.     int firstBlock = (((int)*reqAddr)-VMMACH_SHARED_START_ADDR+
  3941.             VMMACH_SHARED_BLOCK_SIZE-1) /
  3942.             VMMACH_SHARED_BLOCK_SIZE;
  3943.     int i;
  3944.     VmMach_SharedData   *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  3945.  
  3946.     if (fixed==0) {
  3947.         return VmMach_Alloc(sharedData, size, reqAddr);
  3948.     } else {
  3949.         for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  3950.             if (i>0) {
  3951.                 ALLOC(i,numBlocks);
  3952.             }
  3953.         }
  3954.         return SUCCESS;
  3955.     }
  3956. }
  3957.  
  3958. /*
  3959.  * ----------------------------------------------------------------------------
  3960.  *
  3961.  * VmMach_SharedProcStart --
  3962.  *
  3963.  *      Perform machine dependent initialization of shared memory
  3964.  *    for this process.
  3965.  *
  3966.  * Results:
  3967.  *      None.
  3968.  *
  3969.  * Side effects:
  3970.  *      The storage allocation structures are initialized.
  3971.  *
  3972.  * ----------------------------------------------------------------------------
  3973.  */
  3974. void
  3975. VmMach_SharedProcStart(procPtr)
  3976.     Proc_ControlBlock    *procPtr;
  3977. {
  3978.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  3979.     dprintf("VmMach_SharedProcStart: initializing proc's allocVector\n");
  3980.     if (sharedData->allocVector != (int *)NIL) {
  3981.     panic("VmMach_SharedProcStart: allocVector not NIL\n");
  3982.     }
  3983.     sharedData->allocVector =
  3984.         (int *)malloc(VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  3985.     sharedData->allocFirstFree = 0;
  3986.     bzero((Address) sharedData->allocVector, VMMACH_SHARED_NUM_BLOCKS*
  3987.         sizeof(int));
  3988. #if 0
  3989.     procPtr->vmPtr->sharedStart = (Address) VMMACH_SHARED_START_ADDR;
  3990.     procPtr->vmPtr->sharedEnd = (Address) VMMACH_SHARED_START_ADDR +
  3991.         VMMACH_USER_SHARED_PAGES*VMMACH_PAGE_SIZE;
  3992. #else
  3993.     procPtr->vmPtr->sharedStart = (Address) 0x00000000;
  3994.     procPtr->vmPtr->sharedEnd = (Address) 0xffff0000;
  3995.     
  3996. #endif
  3997. }
  3998.  
  3999. /*
  4000.  * ----------------------------------------------------------------------------
  4001.  *
  4002.  * VmMach_SharedSegFinish --
  4003.  *
  4004.  *      Perform machine dependent cleanup of shared memory
  4005.  *    for this segment.
  4006.  *
  4007.  * Results:
  4008.  *      None.
  4009.  *
  4010.  * Side effects:
  4011.  *      The storage allocation structures are freed.
  4012.  *
  4013.  * ----------------------------------------------------------------------------
  4014.  */
  4015. void
  4016. VmMach_SharedSegFinish(procPtr,addr)
  4017.     Proc_ControlBlock    *procPtr;
  4018.     Address        addr;
  4019. {
  4020.     VmMach_Unalloc(&procPtr->vmPtr->machPtr->sharedData,addr);
  4021. }
  4022.  
  4023. /*
  4024.  * ----------------------------------------------------------------------------
  4025.  *
  4026.  * VmMach_SharedProcFinish --
  4027.  *
  4028.  *      Perform machine dependent cleanup of shared memory
  4029.  *    for this process.
  4030.  *
  4031.  * Results:
  4032.  *      None.
  4033.  *
  4034.  * Side effects:
  4035.  *      The storage allocation structures are freed.
  4036.  *
  4037.  * ----------------------------------------------------------------------------
  4038.  */
  4039. void
  4040. VmMach_SharedProcFinish(procPtr)
  4041.     Proc_ControlBlock    *procPtr;
  4042. {
  4043.     dprintf("VmMach_SharedProcFinish: freeing process's allocVector\n");
  4044.     free((Address)procPtr->vmPtr->machPtr->sharedData.allocVector);
  4045.     procPtr->vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  4046. }
  4047.  
  4048. /*
  4049.  * ----------------------------------------------------------------------------
  4050.  *
  4051.  * VmMach_CopySharedMem --
  4052.  *
  4053.  *      Copies machine-dependent shared memory data structures to handle
  4054.  *      a fork.
  4055.  *
  4056.  * Results:
  4057.  *      None.
  4058.  *
  4059.  * Side effects:
  4060.  *      The new process gets a copy of the shared memory structures.
  4061.  *
  4062.  * ----------------------------------------------------------------------------
  4063.  */
  4064. void
  4065. VmMach_CopySharedMem(parentProcPtr, childProcPtr)
  4066.     Proc_ControlBlock   *parentProcPtr; /* Parent process. */
  4067.     Proc_ControlBlock   *childProcPtr;  /* Child process. */
  4068. {
  4069.     VmMach_SharedData   *childSharedData =
  4070.             &childProcPtr->vmPtr->machPtr->sharedData;
  4071.     VmMach_SharedData   *parentSharedData =
  4072.             &parentProcPtr->vmPtr->machPtr->sharedData;
  4073.  
  4074.     VmMach_SharedProcStart(childProcPtr);
  4075.  
  4076.     bcopy((Address)parentSharedData->allocVector,
  4077.         (Address)childSharedData->allocVector,
  4078.             VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  4079.     childSharedData->allocFirstFree = parentSharedData->allocFirstFree;
  4080. }
  4081.  
  4082. /*
  4083.  * ----------------------------------------------------------------------------
  4084.  *
  4085.  * VmMach_LockCachePage --
  4086.  *
  4087.  *      Perform machine dependent locking of a kernel resident file cache
  4088.  *    page.
  4089.  *
  4090.  * Results:
  4091.  *      None.
  4092.  *
  4093.  * Side effects:
  4094.  *
  4095.  * ----------------------------------------------------------------------------
  4096.  */
  4097. void
  4098. VmMach_LockCachePage(kernelAddress)
  4099.     Address    kernelAddress;    /* Address on page to lock. */
  4100. {
  4101.     /*
  4102.      * Sun3 leaves file cache pages always available so there is no need to
  4103.      * lock or unlock them.
  4104.      */
  4105.     return;
  4106. }
  4107.  
  4108. /*
  4109.  * ----------------------------------------------------------------------------
  4110.  *
  4111.  * VmMach_UnlockCachePage --
  4112.  *
  4113.  *      Perform machine dependent unlocking of a kernel resident page.
  4114.  *
  4115.  * Results:
  4116.  *      None.
  4117.  *
  4118.  * Side effects:
  4119.  *
  4120.  * ----------------------------------------------------------------------------
  4121.  */
  4122. void
  4123. VmMach_UnlockCachePage(kernelAddress)
  4124.     Address    kernelAddress;    /* Address on page to unlock. */
  4125. {
  4126.     /*
  4127.      * Sun3 leaves file cache pages always available so there is no need to
  4128.      * lock or unlock them.
  4129.      */
  4130.     return;
  4131. }
  4132.